forked from loafle/openapi-generator-original
New python-fastapi generator (#9611)
* [python-fastapi] Added new generator See https://fastapi.tiangolo.com/ for more details about FastAPI Signed-off-by: Nikita Vakula <programmistov.programmist@gmail.com> * [python-fastapi] Added samples Signed-off-by: Nikita Vakula <programmistov.programmist@gmail.com>
This commit is contained in:
6
bin/configs/python-fastapi.yaml
Normal file
6
bin/configs/python-fastapi.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
generatorName: python-fastapi
|
||||||
|
outputDir: samples/server/petstore/python-fastapi
|
||||||
|
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
|
||||||
|
templateDir: modules/openapi-generator/src/main/resources/python-fastapi
|
||||||
|
additionalProperties:
|
||||||
|
hideGenerationTimestamp: "true"
|
||||||
211
docs/generators/python-fastapi.md
Normal file
211
docs/generators/python-fastapi.md
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
---
|
||||||
|
title: Config Options for python-fastapi
|
||||||
|
sidebar_label: python-fastapi
|
||||||
|
---
|
||||||
|
|
||||||
|
These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
|
||||||
|
|
||||||
|
| Option | Description | Values | Default |
|
||||||
|
| ------ | ----------- | ------ | ------- |
|
||||||
|
|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
|
||||||
|
|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|<dl><dt>**false**</dt><dd>The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.</dd><dt>**true**</dt><dd>Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.</dd></dl>|true|
|
||||||
|
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|
||||||
|
|legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C#have this enabled by default).|<dl><dt>**true**</dt><dd>The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.</dd><dt>**false**</dt><dd>The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.</dd></dl>|true|
|
||||||
|
|packageName|python package name (convention: snake_case).| |openapi_server|
|
||||||
|
|packageVersion|python package version.| |1.0.0|
|
||||||
|
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|
||||||
|
|serverPort|TCP port to listen to in app.run| |8080|
|
||||||
|
|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true|
|
||||||
|
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|
||||||
|
|
||||||
|
## IMPORT MAPPING
|
||||||
|
|
||||||
|
| Type/Alias | Imports |
|
||||||
|
| ---------- | ------- |
|
||||||
|
|
||||||
|
|
||||||
|
## INSTANTIATION TYPES
|
||||||
|
|
||||||
|
| Type/Alias | Instantiated By |
|
||||||
|
| ---------- | --------------- |
|
||||||
|
|
||||||
|
|
||||||
|
## LANGUAGE PRIMITIVES
|
||||||
|
|
||||||
|
<ul class="column-ul">
|
||||||
|
<li>Dict</li>
|
||||||
|
<li>List</li>
|
||||||
|
<li>bool</li>
|
||||||
|
<li>bytes</li>
|
||||||
|
<li>date</li>
|
||||||
|
<li>datetime</li>
|
||||||
|
<li>dict</li>
|
||||||
|
<li>file</li>
|
||||||
|
<li>float</li>
|
||||||
|
<li>int</li>
|
||||||
|
<li>list</li>
|
||||||
|
<li>object</li>
|
||||||
|
<li>str</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
## RESERVED WORDS
|
||||||
|
|
||||||
|
<ul class="column-ul">
|
||||||
|
<li>all_params</li>
|
||||||
|
<li>and</li>
|
||||||
|
<li>as</li>
|
||||||
|
<li>assert</li>
|
||||||
|
<li>async</li>
|
||||||
|
<li>auth_settings</li>
|
||||||
|
<li>await</li>
|
||||||
|
<li>body_params</li>
|
||||||
|
<li>break</li>
|
||||||
|
<li>class</li>
|
||||||
|
<li>continue</li>
|
||||||
|
<li>def</li>
|
||||||
|
<li>del</li>
|
||||||
|
<li>elif</li>
|
||||||
|
<li>else</li>
|
||||||
|
<li>except</li>
|
||||||
|
<li>exec</li>
|
||||||
|
<li>false</li>
|
||||||
|
<li>finally</li>
|
||||||
|
<li>for</li>
|
||||||
|
<li>form_params</li>
|
||||||
|
<li>from</li>
|
||||||
|
<li>global</li>
|
||||||
|
<li>header_params</li>
|
||||||
|
<li>if</li>
|
||||||
|
<li>import</li>
|
||||||
|
<li>in</li>
|
||||||
|
<li>is</li>
|
||||||
|
<li>lambda</li>
|
||||||
|
<li>local_var_files</li>
|
||||||
|
<li>none</li>
|
||||||
|
<li>nonlocal</li>
|
||||||
|
<li>not</li>
|
||||||
|
<li>or</li>
|
||||||
|
<li>pass</li>
|
||||||
|
<li>path_params</li>
|
||||||
|
<li>print</li>
|
||||||
|
<li>property</li>
|
||||||
|
<li>query_params</li>
|
||||||
|
<li>raise</li>
|
||||||
|
<li>resource_path</li>
|
||||||
|
<li>return</li>
|
||||||
|
<li>self</li>
|
||||||
|
<li>true</li>
|
||||||
|
<li>try</li>
|
||||||
|
<li>while</li>
|
||||||
|
<li>with</li>
|
||||||
|
<li>yield</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
## FEATURE SET
|
||||||
|
|
||||||
|
|
||||||
|
### Client Modification Feature
|
||||||
|
| Name | Supported | Defined By |
|
||||||
|
| ---- | --------- | ---------- |
|
||||||
|
|BasePath|✗|ToolingExtension
|
||||||
|
|Authorizations|✗|ToolingExtension
|
||||||
|
|UserAgent|✗|ToolingExtension
|
||||||
|
|MockServer|✗|ToolingExtension
|
||||||
|
|
||||||
|
### Data Type Feature
|
||||||
|
| Name | Supported | Defined By |
|
||||||
|
| ---- | --------- | ---------- |
|
||||||
|
|Custom|✗|OAS2,OAS3
|
||||||
|
|Int32|✓|OAS2,OAS3
|
||||||
|
|Int64|✓|OAS2,OAS3
|
||||||
|
|Float|✓|OAS2,OAS3
|
||||||
|
|Double|✓|OAS2,OAS3
|
||||||
|
|Decimal|✓|ToolingExtension
|
||||||
|
|String|✓|OAS2,OAS3
|
||||||
|
|Byte|✓|OAS2,OAS3
|
||||||
|
|Binary|✓|OAS2,OAS3
|
||||||
|
|Boolean|✓|OAS2,OAS3
|
||||||
|
|Date|✓|OAS2,OAS3
|
||||||
|
|DateTime|✓|OAS2,OAS3
|
||||||
|
|Password|✓|OAS2,OAS3
|
||||||
|
|File|✓|OAS2
|
||||||
|
|Array|✓|OAS2,OAS3
|
||||||
|
|Maps|✓|ToolingExtension
|
||||||
|
|CollectionFormat|✓|OAS2
|
||||||
|
|CollectionFormatMulti|✓|OAS2
|
||||||
|
|Enum|✓|OAS2,OAS3
|
||||||
|
|ArrayOfEnum|✓|ToolingExtension
|
||||||
|
|ArrayOfModel|✓|ToolingExtension
|
||||||
|
|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
|
||||||
|
|ArrayOfCollectionOfModel|✓|ToolingExtension
|
||||||
|
|ArrayOfCollectionOfEnum|✓|ToolingExtension
|
||||||
|
|MapOfEnum|✓|ToolingExtension
|
||||||
|
|MapOfModel|✓|ToolingExtension
|
||||||
|
|MapOfCollectionOfPrimitives|✓|ToolingExtension
|
||||||
|
|MapOfCollectionOfModel|✓|ToolingExtension
|
||||||
|
|MapOfCollectionOfEnum|✓|ToolingExtension
|
||||||
|
|
||||||
|
### Documentation Feature
|
||||||
|
| Name | Supported | Defined By |
|
||||||
|
| ---- | --------- | ---------- |
|
||||||
|
|Readme|✗|ToolingExtension
|
||||||
|
|Model|✓|ToolingExtension
|
||||||
|
|Api|✓|ToolingExtension
|
||||||
|
|
||||||
|
### Global Feature
|
||||||
|
| Name | Supported | Defined By |
|
||||||
|
| ---- | --------- | ---------- |
|
||||||
|
|Host|✓|OAS2,OAS3
|
||||||
|
|BasePath|✓|OAS2,OAS3
|
||||||
|
|Info|✓|OAS2,OAS3
|
||||||
|
|Schemes|✗|OAS2,OAS3
|
||||||
|
|PartialSchemes|✓|OAS2,OAS3
|
||||||
|
|Consumes|✓|OAS2
|
||||||
|
|Produces|✓|OAS2
|
||||||
|
|ExternalDocumentation|✓|OAS2,OAS3
|
||||||
|
|Examples|✓|OAS2,OAS3
|
||||||
|
|XMLStructureDefinitions|✗|OAS2,OAS3
|
||||||
|
|MultiServer|✗|OAS3
|
||||||
|
|ParameterizedServer|✗|OAS3
|
||||||
|
|ParameterStyling|✗|OAS3
|
||||||
|
|Callbacks|✓|OAS3
|
||||||
|
|LinkObjects|✗|OAS3
|
||||||
|
|
||||||
|
### Parameter Feature
|
||||||
|
| Name | Supported | Defined By |
|
||||||
|
| ---- | --------- | ---------- |
|
||||||
|
|Path|✓|OAS2,OAS3
|
||||||
|
|Query|✓|OAS2,OAS3
|
||||||
|
|Header|✓|OAS2,OAS3
|
||||||
|
|Body|✓|OAS2
|
||||||
|
|FormUnencoded|✓|OAS2
|
||||||
|
|FormMultipart|✓|OAS2
|
||||||
|
|Cookie|✓|OAS3
|
||||||
|
|
||||||
|
### Schema Support Feature
|
||||||
|
| Name | Supported | Defined By |
|
||||||
|
| ---- | --------- | ---------- |
|
||||||
|
|Simple|✓|OAS2,OAS3
|
||||||
|
|Composite|✓|OAS2,OAS3
|
||||||
|
|Polymorphism|✓|OAS2,OAS3
|
||||||
|
|Union|✗|OAS3
|
||||||
|
|
||||||
|
### Security Feature
|
||||||
|
| Name | Supported | Defined By |
|
||||||
|
| ---- | --------- | ---------- |
|
||||||
|
|BasicAuth|✓|OAS2,OAS3
|
||||||
|
|ApiKey|✓|OAS2,OAS3
|
||||||
|
|OpenIDConnect|✗|OAS3
|
||||||
|
|BearerToken|✓|OAS3
|
||||||
|
|OAuth2_Implicit|✓|OAS2,OAS3
|
||||||
|
|OAuth2_Password|✓|OAS2,OAS3
|
||||||
|
|OAuth2_ClientCredentials|✓|OAS2,OAS3
|
||||||
|
|OAuth2_AuthorizationCode|✓|OAS2,OAS3
|
||||||
|
|
||||||
|
### Wire Format Feature
|
||||||
|
| Name | Supported | Defined By |
|
||||||
|
| ---- | --------- | ---------- |
|
||||||
|
|JSON|✓|OAS2,OAS3
|
||||||
|
|XML|✓|OAS2,OAS3
|
||||||
|
|PROTOBUF|✗|ToolingExtension
|
||||||
|
|Custom|✗|OAS2,OAS3
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
package org.openapitools.codegen.languages;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
import io.swagger.v3.oas.models.media.ArraySchema;
|
||||||
|
import io.swagger.v3.oas.models.media.Schema;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.openapitools.codegen.*;
|
||||||
|
import org.openapitools.codegen.utils.ModelUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.openapitools.codegen.utils.StringUtils.underscore;
|
||||||
|
|
||||||
|
public class PythonFastAPIServerCodegen extends AbstractPythonCodegen {
|
||||||
|
private static class SnakeCaseKeySerializer extends JsonSerializer<String> {
|
||||||
|
@Override
|
||||||
|
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||||
|
gen.writeFieldName(underscore(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PythonBooleanSerializer extends JsonSerializer<Boolean> {
|
||||||
|
@Override
|
||||||
|
public void serialize(Boolean value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||||
|
gen.writeNumber(value ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// An object mapper that is used to convert an example string to
|
||||||
|
// a "python-compliant" example string (keys in snake case, boolean as 1/0).
|
||||||
|
final ObjectMapper MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
|
final Logger LOGGER = LoggerFactory.getLogger(PythonFastAPIServerCodegen.class);
|
||||||
|
|
||||||
|
private static final String NAME = "python-fastapi";
|
||||||
|
private static final int DEFAULT_SERVER_PORT = 8080;
|
||||||
|
private static final String DEFAULT_PACKAGE_NAME = "openapi_server";
|
||||||
|
private static final String SRC_DIR = "src";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CodegenType getTag() {
|
||||||
|
return CodegenType.SERVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHelp() {
|
||||||
|
return "Generates a python server (FastAPI).";
|
||||||
|
}
|
||||||
|
|
||||||
|
public PythonFastAPIServerCodegen() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
SimpleModule simpleModule = new SimpleModule();
|
||||||
|
simpleModule.addKeySerializer(String.class, new SnakeCaseKeySerializer());
|
||||||
|
simpleModule.addSerializer(Boolean.class, new PythonBooleanSerializer());
|
||||||
|
MAPPER.registerModule(simpleModule);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Additional Properties. These values can be passed to the templates and
|
||||||
|
* are available in models, apis, and supporting files
|
||||||
|
*/
|
||||||
|
additionalProperties.put("serverPort", DEFAULT_SERVER_PORT);
|
||||||
|
additionalProperties.put(CodegenConstants.PACKAGE_NAME, DEFAULT_PACKAGE_NAME);
|
||||||
|
|
||||||
|
languageSpecificPrimitives.add("List");
|
||||||
|
languageSpecificPrimitives.add("Dict");
|
||||||
|
typeMapping.put("array", "List");
|
||||||
|
typeMapping.put("map", "Dict");
|
||||||
|
|
||||||
|
outputFolder = "generated-code" + File.separator + NAME;
|
||||||
|
modelTemplateFiles.put("model.mustache", ".py");
|
||||||
|
apiTemplateFiles.put("api.mustache", ".py");
|
||||||
|
embeddedTemplateDir = templateDir = NAME;
|
||||||
|
apiPackage = "apis";
|
||||||
|
modelPackage = "models";
|
||||||
|
testPackage = "tests";
|
||||||
|
apiTestTemplateFiles().put("api_test.mustache", ".py");
|
||||||
|
|
||||||
|
cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "python package name (convention: snake_case).")
|
||||||
|
.defaultValue(DEFAULT_PACKAGE_NAME));
|
||||||
|
cliOptions.add(new CliOption(CodegenConstants.PACKAGE_VERSION, "python package version.")
|
||||||
|
.defaultValue("1.0.0"));
|
||||||
|
cliOptions.add(new CliOption("serverPort", "TCP port to listen to in app.run").
|
||||||
|
defaultValue(String.valueOf(DEFAULT_SERVER_PORT)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processOpts() {
|
||||||
|
super.processOpts();
|
||||||
|
|
||||||
|
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
|
||||||
|
setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
modelPackage = packageName + "." + modelPackage;
|
||||||
|
apiPackage = packageName + "." + apiPackage;
|
||||||
|
|
||||||
|
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
|
||||||
|
supportingFiles.add(new SupportingFile("openapi.mustache", "", "openapi.yaml"));
|
||||||
|
supportingFiles.add(new SupportingFile("main.mustache", SRC_DIR + File.separator + packageName.replace('.', File.separatorChar), "main.py"));
|
||||||
|
supportingFiles.add(new SupportingFile("docker-compose.mustache", "", "docker-compose.yaml"));
|
||||||
|
supportingFiles.add(new SupportingFile("Dockerfile.mustache", "", "Dockerfile"));
|
||||||
|
supportingFiles.add(new SupportingFile("requirements.mustache", "", "requirements.txt"));
|
||||||
|
supportingFiles.add(new SupportingFile("security_api.mustache", SRC_DIR + File.separator + packageName.replace('.', File.separatorChar), "security_api.py"));
|
||||||
|
supportingFiles.add(new SupportingFile("extra_models.mustache", StringUtils.substringAfter(modelFileFolder(), outputFolder), "extra_models.py"));
|
||||||
|
|
||||||
|
// Add __init__.py to all sub-folders under namespace pkg
|
||||||
|
StringBuilder namespacePackagePath = new StringBuilder(SRC_DIR + File.separator + StringUtils.substringBefore(packageName, "."));
|
||||||
|
for (String tmp: StringUtils.split(StringUtils.substringAfter(packageName, "."), '.')) {
|
||||||
|
namespacePackagePath.append(File.separator).append(tmp);
|
||||||
|
supportingFiles.add(new SupportingFile("__init__.mustache", namespacePackagePath.toString(), "__init__.py"));
|
||||||
|
}
|
||||||
|
supportingFiles.add(new SupportingFile("__init__.mustache", StringUtils.substringAfter(modelFileFolder(), outputFolder), "__init__.py"));
|
||||||
|
supportingFiles.add(new SupportingFile("__init__.mustache", StringUtils.substringAfter(apiFileFolder(), outputFolder), "__init__.py"));
|
||||||
|
|
||||||
|
supportingFiles.add(new SupportingFile("conftest.mustache", testPackage.replace('.', File.separatorChar), "conftest.py"));
|
||||||
|
|
||||||
|
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
|
||||||
|
supportingFiles.add(new SupportingFile("pyproject_toml.mustache", "", "pyproject.toml"));
|
||||||
|
supportingFiles.add(new SupportingFile("setup_cfg.mustache", "", "setup.cfg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toModelImport(String name) {
|
||||||
|
String modelImport;
|
||||||
|
if (StringUtils.startsWithAny(name, "import", "from")) {
|
||||||
|
modelImport = name;
|
||||||
|
} else {
|
||||||
|
modelImport = "from ";
|
||||||
|
if (!"".equals(modelPackage())) {
|
||||||
|
modelImport += modelPackage() + ".";
|
||||||
|
}
|
||||||
|
modelImport += toModelFilename(name) + " import " + name;
|
||||||
|
}
|
||||||
|
return modelImport;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTypeDeclaration(Schema p) {
|
||||||
|
if (ModelUtils.isArraySchema(p)) {
|
||||||
|
ArraySchema ap = (ArraySchema) p;
|
||||||
|
Schema inner = ap.getItems();
|
||||||
|
return getSchemaType(p) + "[" + getTypeDeclaration(inner) + "]";
|
||||||
|
} else if (ModelUtils.isMapSchema(p)) {
|
||||||
|
Schema inner = getAdditionalProperties(p);
|
||||||
|
return getSchemaType(p) + "[str, " + getTypeDeclaration(inner) + "]";
|
||||||
|
}
|
||||||
|
return super.getTypeDeclaration(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
|
||||||
|
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
|
||||||
|
// Set will make sure that no duplicated items are used.
|
||||||
|
Set<String> securityImports = new HashSet<>();
|
||||||
|
if (operations != null) {
|
||||||
|
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
|
||||||
|
for (final CodegenOperation operation : ops) {
|
||||||
|
List<CodegenResponse> responses = operation.responses;
|
||||||
|
if (responses != null) {
|
||||||
|
for (final CodegenResponse resp : responses) {
|
||||||
|
// Convert "default" value (0) to OK (200).
|
||||||
|
if ("0".equals(resp.code)) {
|
||||||
|
resp.code = "200";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<CodegenSecurity> securityMethods = operation.authMethods;
|
||||||
|
if (securityMethods != null) {
|
||||||
|
for (final CodegenSecurity securityMethod: securityMethods) {
|
||||||
|
securityImports.add(securityMethod.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.requestBodyExamples != null) {
|
||||||
|
for (Map<String, String> example : operation.requestBodyExamples) {
|
||||||
|
if (example.get("contentType") != null && example.get("contentType").equals("application/json")) {
|
||||||
|
// Make an example dictionary more python-like (snake-case, etc.).
|
||||||
|
// If fails, use the original string.
|
||||||
|
try {
|
||||||
|
Map<String, Object> result = MAPPER.readValue(example.get("example"),
|
||||||
|
new TypeReference<Map<String, Object>>(){});
|
||||||
|
operation.bodyParam.example = MAPPER.writeValueAsString(result);
|
||||||
|
} catch (IOException e) {
|
||||||
|
operation.bodyParam.example = example.get("example");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
objs.put("securityImports", new ArrayList<String>(securityImports));
|
||||||
|
|
||||||
|
return objs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
|
||||||
|
Map<String, Object> result = super.postProcessAllModels(objs);
|
||||||
|
for (Map.Entry<String, Object> entry : result.entrySet()) {
|
||||||
|
Map<String, Object> inner = (Map<String, Object>) entry.getValue();
|
||||||
|
List<Map<String, Object>> models = (List<Map<String, Object>>) inner.get("models");
|
||||||
|
for (Map<String, Object> mo : models) {
|
||||||
|
CodegenModel cm = (CodegenModel) mo.get("model");
|
||||||
|
// Add additional filename information for imports
|
||||||
|
mo.put("pyImports", toPyImports(cm, cm.imports));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Map<String, String>> toPyImports(CodegenModel cm, Set<String> imports) {
|
||||||
|
List<Map<String, String>> pyImports = new ArrayList<>();
|
||||||
|
for (String im : imports) {
|
||||||
|
if (!im.equals(cm.classname)) {
|
||||||
|
HashMap<String, String> pyImport = new HashMap<>();
|
||||||
|
pyImport.put("import", toModelImport(im));
|
||||||
|
pyImports.add(pyImport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pyImports;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
|
||||||
|
generateYAMLSpecFile(objs);
|
||||||
|
return objs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String apiFileFolder() {
|
||||||
|
return outputFolder + File.separator + SRC_DIR + File.separator + apiPackage().replace('.', File.separatorChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String modelFileFolder() {
|
||||||
|
return outputFolder + File.separator + SRC_DIR + File.separator + modelPackage().replace('.', File.separatorChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -97,6 +97,7 @@ org.openapitools.codegen.languages.PowerShellClientCodegen
|
|||||||
org.openapitools.codegen.languages.ProtobufSchemaCodegen
|
org.openapitools.codegen.languages.ProtobufSchemaCodegen
|
||||||
org.openapitools.codegen.languages.PythonLegacyClientCodegen
|
org.openapitools.codegen.languages.PythonLegacyClientCodegen
|
||||||
org.openapitools.codegen.languages.PythonClientCodegen
|
org.openapitools.codegen.languages.PythonClientCodegen
|
||||||
|
org.openapitools.codegen.languages.PythonFastAPIServerCodegen
|
||||||
org.openapitools.codegen.languages.PythonFlaskConnexionServerCodegen
|
org.openapitools.codegen.languages.PythonFlaskConnexionServerCodegen
|
||||||
org.openapitools.codegen.languages.PythonAiohttpConnexionServerCodegen
|
org.openapitools.codegen.languages.PythonAiohttpConnexionServerCodegen
|
||||||
org.openapitools.codegen.languages.PythonBluePlanetServerCodegen
|
org.openapitools.codegen.languages.PythonBluePlanetServerCodegen
|
||||||
|
|||||||
30
modules/openapi-generator/src/main/resources/python-fastapi/Dockerfile.mustache
vendored
Normal file
30
modules/openapi-generator/src/main/resources/python-fastapi/Dockerfile.mustache
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
FROM python:3.6 AS builder
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
RUN python3 -m venv /venv
|
||||||
|
ENV PATH="/venv/bin:$PATH"
|
||||||
|
|
||||||
|
RUN pip install --upgrade pip
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN pip install --no-cache-dir .
|
||||||
|
|
||||||
|
|
||||||
|
FROM python:3.6 AS test_runner
|
||||||
|
WORKDIR /tmp
|
||||||
|
COPY --from=builder /venv /venv
|
||||||
|
COPY --from=builder /usr/src/app/tests tests
|
||||||
|
ENV PATH=/venv/bin:$PATH
|
||||||
|
|
||||||
|
# install test dependencies
|
||||||
|
RUN pip install pytest
|
||||||
|
|
||||||
|
# run tests
|
||||||
|
RUN pytest tests
|
||||||
|
|
||||||
|
|
||||||
|
FROM python:3.6 AS service
|
||||||
|
WORKDIR /root/app/site-packages
|
||||||
|
COPY --from=test_runner /venv /venv
|
||||||
|
ENV PATH=/venv/bin:$PATH
|
||||||
32
modules/openapi-generator/src/main/resources/python-fastapi/README.mustache
vendored
Normal file
32
modules/openapi-generator/src/main/resources/python-fastapi/README.mustache
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# OpenAPI generated FastAPI server
|
||||||
|
|
||||||
|
This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
|
||||||
|
|
||||||
|
- API version: {{appVersion}}
|
||||||
|
{{^hideGenerationTimestamp}}
|
||||||
|
- Build date: {{generatedDate}}
|
||||||
|
{{/hideGenerationTimestamp}}
|
||||||
|
- Build package: {{generatorClass}}
|
||||||
|
|
||||||
|
## Requirements.
|
||||||
|
|
||||||
|
Python >= 3.6
|
||||||
|
|
||||||
|
## Installation & Usage
|
||||||
|
|
||||||
|
To run the server, please execute the following from the root directory:
|
||||||
|
|
||||||
|
```
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
uvicorn main:app --host 0.0.0.0 --port {{serverPort}}
|
||||||
|
```
|
||||||
|
|
||||||
|
and open your browser at `http://localhost:{{serverPort}}/docs/` to see the docs.
|
||||||
|
|
||||||
|
## Running with Docker
|
||||||
|
|
||||||
|
To run the server on a Docker container, please execute the following from the root directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up --build
|
||||||
|
```
|
||||||
0
modules/openapi-generator/src/main/resources/python-fastapi/__init__.mustache
vendored
Normal file
0
modules/openapi-generator/src/main/resources/python-fastapi/__init__.mustache
vendored
Normal file
64
modules/openapi-generator/src/main/resources/python-fastapi/api.mustache
vendored
Normal file
64
modules/openapi-generator/src/main/resources/python-fastapi/api.mustache
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
from fastapi import (
|
||||||
|
APIRouter,
|
||||||
|
Body,
|
||||||
|
Cookie,
|
||||||
|
Depends,
|
||||||
|
Form,
|
||||||
|
Header,
|
||||||
|
Path,
|
||||||
|
Query,
|
||||||
|
Response,
|
||||||
|
Security,
|
||||||
|
status,
|
||||||
|
)
|
||||||
|
|
||||||
|
from {{modelPackage}}.extra_models import TokenModel
|
||||||
|
{{#imports}}
|
||||||
|
{{import}}
|
||||||
|
{{/imports}}
|
||||||
|
{{#securityImports.0}}from {{packageName}}.security_api import {{#securityImports}}get_token_{{.}}{{^-last}}, {{/-last}}{{/securityImports}}{{/securityImports.0}}
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
{{#operations}}
|
||||||
|
{{#operation}}
|
||||||
|
@router.{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}(
|
||||||
|
"{{path}}",
|
||||||
|
responses={
|
||||||
|
{{#responses}}
|
||||||
|
{{code}}: {{=<% %>=}}{<%#dataType%>"model": <%dataType%>, "description": "<%message%>"<%/dataType%><%^dataType%>"description": "<%message%>"<%/dataType%>}<%={{ }}=%>,
|
||||||
|
{{/responses}}
|
||||||
|
},
|
||||||
|
tags=[{{#tags}}"{{name}}"{{^-last}},{{/-last}}{{/tags}}],
|
||||||
|
{{#summary}}
|
||||||
|
summary="{{summary}}",
|
||||||
|
{{/summary}}
|
||||||
|
{{#description}}
|
||||||
|
description = "{{description}}",
|
||||||
|
{{/description}}
|
||||||
|
)
|
||||||
|
async def {{operationId}}(
|
||||||
|
{{#allParams}}
|
||||||
|
{{>endpoint_argument_definition}},
|
||||||
|
{{/allParams}}
|
||||||
|
{{#hasAuthMethods}}
|
||||||
|
{{#authMethods}}
|
||||||
|
token_{{name}}: TokenModel = Security(
|
||||||
|
get_token_{{name}}{{#isOAuth}}, scopes=[{{#scopes}}"{{scope}}"{{^-last}}, {{/-last}}{{/scopes}}]{{/isOAuth}}
|
||||||
|
),
|
||||||
|
{{/authMethods}}
|
||||||
|
{{/hasAuthMethods}}
|
||||||
|
) -> {{#returnType}}{{.}}{{/returnType}}{{^returnType}}None{{/returnType}}: # noqa: E501
|
||||||
|
{{#notes}}"""{{.}}"""
|
||||||
|
...{{/notes}}{{^notes}}...{{/notes}}
|
||||||
|
{{^-last}}
|
||||||
|
|
||||||
|
|
||||||
|
{{/-last}}
|
||||||
|
{{/operation}}
|
||||||
|
{{/operations}}
|
||||||
53
modules/openapi-generator/src/main/resources/python-fastapi/api_test.mustache
vendored
Normal file
53
modules/openapi-generator/src/main/resources/python-fastapi/api_test.mustache
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
{{#imports}}{{import}}
|
||||||
|
{{/imports}}
|
||||||
|
|
||||||
|
{{#operations}}
|
||||||
|
{{#operation}}
|
||||||
|
|
||||||
|
{{#vendorExtensions.x-skip-test}}
|
||||||
|
@pytest.mark.skip("{{reason}}")
|
||||||
|
{{/vendorExtensions.x-skip-test}}
|
||||||
|
def test_{{operationId}}(client: TestClient):
|
||||||
|
"""Test case for {{{operationId}}}
|
||||||
|
|
||||||
|
{{{summary}}}
|
||||||
|
"""
|
||||||
|
{{#bodyParam}}
|
||||||
|
{{paramName}} = {{#isContainer}}[{{/isContainer}}{{{example}}}{{#isContainer}}]{{/isContainer}}
|
||||||
|
{{/bodyParam}}
|
||||||
|
{{#queryParams}}
|
||||||
|
{{#-first}}params = [{{/-first}}{{^-first}} {{/-first}}("{{paramName}}", {{{example}}}){{^-last}},{{/-last}}{{#-last}}]{{/-last}}
|
||||||
|
{{/queryParams}}
|
||||||
|
headers = { {{#headerParams}}
|
||||||
|
'{{paramName}}': {{{example}}},{{/headerParams}}{{#authMethods}}
|
||||||
|
{{#isOAuth}}'Authorization': 'Bearer special-key',{{/isOAuth}}{{#isApiKey}}'{{name}}': 'special-key',{{/isApiKey}}{{#isBasicBasic}}'Authorization': 'BasicZm9vOmJhcg==',{{/isBasicBasic}}{{#isBasicBearer}}'Authorization': 'Bearer special-key',{{/isBasicBearer}}{{/authMethods}}
|
||||||
|
}
|
||||||
|
{{#formParams}}
|
||||||
|
{{#-first}}
|
||||||
|
data = {
|
||||||
|
{{/-first}}
|
||||||
|
'{{paramName}}': {{{example}}}{{^-last}},{{/-last}}
|
||||||
|
{{#-last}}
|
||||||
|
}
|
||||||
|
{{/-last}}
|
||||||
|
{{/formParams}}
|
||||||
|
response = client.request(
|
||||||
|
'{{httpMethod}}',
|
||||||
|
'{{{path}}}'{{#pathParams}}{{#-first}}.format({{/-first}}{{baseName}}={{{example}}}{{^-last}}, {{/-last}}{{#-last}}){{/-last}}{{/pathParams}},
|
||||||
|
headers=headers,{{#bodyParam}}
|
||||||
|
json={{paramName}},{{/bodyParam}}{{#formParams}}{{#-first}}
|
||||||
|
data=data,{{/-first}}{{/formParams}}{{#queryParams}}{{#-first}}
|
||||||
|
params=params,{{/-first}}{{/queryParams}}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
{{/operation}}
|
||||||
|
{{/operations}}
|
||||||
20
modules/openapi-generator/src/main/resources/python-fastapi/conftest.mustache
vendored
Normal file
20
modules/openapi-generator/src/main/resources/python-fastapi/conftest.mustache
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import contextlib
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
from {{packageName}}.main import app as application
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def app() -> FastAPI:
|
||||||
|
application.dependency_overrides = {}
|
||||||
|
|
||||||
|
return application
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def client(app) -> TestClient:
|
||||||
|
return TestClient(app)
|
||||||
9
modules/openapi-generator/src/main/resources/python-fastapi/docker-compose.mustache
vendored
Normal file
9
modules/openapi-generator/src/main/resources/python-fastapi/docker-compose.mustache
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
version: '3.6'
|
||||||
|
services:
|
||||||
|
service:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: service
|
||||||
|
ports:
|
||||||
|
- "{{serverPort}}:{{serverPort}}"
|
||||||
|
command: uvicorn {{packageName}}.main:app --host 0.0.0.0 --port {{serverPort}}
|
||||||
@@ -0,0 +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}}(None, description="{{description}}")
|
||||||
8
modules/openapi-generator/src/main/resources/python-fastapi/extra_models.mustache
vendored
Normal file
8
modules/openapi-generator/src/main/resources/python-fastapi/extra_models.mustache
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
class TokenModel(BaseModel):
|
||||||
|
"""Defines a token model."""
|
||||||
|
|
||||||
|
sub: str
|
||||||
138
modules/openapi-generator/src/main/resources/python-fastapi/gitignore.mustache
vendored
Normal file
138
modules/openapi-generator/src/main/resources/python-fastapi/gitignore.mustache
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
23
modules/openapi-generator/src/main/resources/python-fastapi/main.mustache
vendored
Normal file
23
modules/openapi-generator/src/main/resources/python-fastapi/main.mustache
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
{{>partial_header}}
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
from {{apiPackage}}.{{classFilename}} import router as {{classname}}Router
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
title="{{appName}}",
|
||||||
|
description="{{appDescription}}",
|
||||||
|
version="{{appVersion}}",
|
||||||
|
)
|
||||||
|
|
||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
app.include_router({{classname}}Router)
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
35
modules/openapi-generator/src/main/resources/python-fastapi/model.mustache
vendored
Normal file
35
modules/openapi-generator/src/main/resources/python-fastapi/model.mustache
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, EmailStr, validator
|
||||||
|
{{#models}}
|
||||||
|
{{#model}}
|
||||||
|
{{#pyImports}}
|
||||||
|
{{import}}
|
||||||
|
{{/pyImports}}
|
||||||
|
{{/model}}
|
||||||
|
{{/models}}
|
||||||
|
|
||||||
|
|
||||||
|
{{#models}}
|
||||||
|
{{#model}}
|
||||||
|
class {{classname}}(BaseModel):
|
||||||
|
"""NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
|
||||||
|
Do not edit the class manually.
|
||||||
|
|
||||||
|
{{classname}} - a model defined in OpenAPI
|
||||||
|
|
||||||
|
{{#vars}}
|
||||||
|
{{name}}: The {{name}} of this {{classname}}{{^required}} [Optional]{{/required}}.
|
||||||
|
{{/vars}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
{{#vars}}
|
||||||
|
{{name}}: {{#required}}{{dataType}}{{/required}}{{^required}}Optional[{{dataType}}] = None{{/required}}
|
||||||
|
{{/vars}}
|
||||||
|
{{/model}}
|
||||||
|
{{/models}}
|
||||||
1
modules/openapi-generator/src/main/resources/python-fastapi/openapi.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/python-fastapi/openapi.mustache
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{{{openapi-yaml}}}
|
||||||
1
modules/openapi-generator/src/main/resources/python-fastapi/param_type.mustache
vendored
Normal file
1
modules/openapi-generator/src/main/resources/python-fastapi/param_type.mustache
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{{#isString}}str{{/isString}}{{#isInteger}}int{{/isInteger}}{{#isLong}}int{{/isLong}}{{#isFloat}}float{{/isFloat}}{{#isDouble}}float{{/isDouble}}{{#isByteArray}}str{{/isByteArray}}{{#isBinary}}str{{/isBinary}}{{#isBoolean}}bool{{/isBoolean}}{{#isDate}}str{{/isDate}}{{#isDateTime}}str{{/isDateTime}}{{#isModel}}{{dataType}}{{/isModel}}{{#isContainer}}{{dataType}}{{/isContainer}}
|
||||||
17
modules/openapi-generator/src/main/resources/python-fastapi/partial_header.mustache
vendored
Normal file
17
modules/openapi-generator/src/main/resources/python-fastapi/partial_header.mustache
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
"""
|
||||||
|
{{#appName}}
|
||||||
|
{{{appName}}}
|
||||||
|
{{/appName}}
|
||||||
|
|
||||||
|
{{#appDescription}}
|
||||||
|
{{{appDescription}}}
|
||||||
|
{{/appDescription}}
|
||||||
|
|
||||||
|
{{#version}}
|
||||||
|
The version of the OpenAPI document: {{{version}}}
|
||||||
|
{{/version}}
|
||||||
|
{{#infoEmail}}
|
||||||
|
Contact: {{{infoEmail}}}
|
||||||
|
{{/infoEmail}}
|
||||||
|
Generated by: https://openapi-generator.tech
|
||||||
|
"""
|
||||||
30
modules/openapi-generator/src/main/resources/python-fastapi/pyproject_toml.mustache
vendored
Normal file
30
modules/openapi-generator/src/main/resources/python-fastapi/pyproject_toml.mustache
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[tool.black]
|
||||||
|
line-length = 88
|
||||||
|
exclude = '''
|
||||||
|
(
|
||||||
|
/(
|
||||||
|
\.eggs # exclude a few common directories in the
|
||||||
|
| \.git # root of the project
|
||||||
|
| \.hg
|
||||||
|
| \.mypy_cache
|
||||||
|
| \.tox
|
||||||
|
| \.venv
|
||||||
|
| _build
|
||||||
|
| buck-out
|
||||||
|
| build
|
||||||
|
| dist
|
||||||
|
)/
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
profile = "black"
|
||||||
|
skip = [
|
||||||
|
'.eggs', '.git', '.hg', '.mypy_cache', '.nox', '.pants.d', '.tox',
|
||||||
|
'.venv', '_build', 'buck-out', 'build', 'dist', 'node_modules', 'venv',
|
||||||
|
]
|
||||||
|
skip_gitignore = true
|
||||||
36
modules/openapi-generator/src/main/resources/python-fastapi/requirements.mustache
vendored
Normal file
36
modules/openapi-generator/src/main/resources/python-fastapi/requirements.mustache
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
aiofiles==0.5.0
|
||||||
|
aniso8601==7.0.0
|
||||||
|
async-exit-stack==1.0.1
|
||||||
|
async-generator==1.10
|
||||||
|
certifi==2020.12.5
|
||||||
|
chardet==4.0.0
|
||||||
|
click==7.1.2
|
||||||
|
dnspython==2.1.0
|
||||||
|
email-validator==1.1.2
|
||||||
|
fastapi==0.65.1
|
||||||
|
graphene==2.1.8
|
||||||
|
graphql-core==2.3.2
|
||||||
|
graphql-relay==2.0.1
|
||||||
|
h11==0.12.0
|
||||||
|
httptools==0.1.2
|
||||||
|
idna==2.10
|
||||||
|
itsdangerous==1.1.0
|
||||||
|
Jinja2==2.11.3
|
||||||
|
MarkupSafe==2.0.1
|
||||||
|
orjson==3.5.2
|
||||||
|
promise==2.3
|
||||||
|
pydantic==1.8.2
|
||||||
|
python-dotenv==0.17.1
|
||||||
|
python-multipart==0.0.5
|
||||||
|
PyYAML==5.4.1
|
||||||
|
requests==2.25.1
|
||||||
|
Rx==1.6.1
|
||||||
|
six==1.16.0
|
||||||
|
starlette==0.14.2
|
||||||
|
typing-extensions==3.10.0.0
|
||||||
|
ujson==4.0.2
|
||||||
|
urllib3==1.26.4
|
||||||
|
uvicorn==0.13.4
|
||||||
|
uvloop==0.14.0
|
||||||
|
watchgod==0.7
|
||||||
|
websockets==8.1
|
||||||
157
modules/openapi-generator/src/main/resources/python-fastapi/security_api.mustache
vendored
Normal file
157
modules/openapi-generator/src/main/resources/python-fastapi/security_api.mustache
vendored
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, Response, Security, status
|
||||||
|
from fastapi.openapi.models import OAuthFlowImplicit, OAuthFlows
|
||||||
|
from fastapi.security import (
|
||||||
|
HTTPAuthorizationCredentials,
|
||||||
|
HTTPBasic,
|
||||||
|
HTTPBasicCredentials,
|
||||||
|
HTTPBearer,
|
||||||
|
OAuth2,
|
||||||
|
OAuth2AuthorizationCodeBearer,
|
||||||
|
OAuth2PasswordBearer,
|
||||||
|
SecurityScopes,
|
||||||
|
)
|
||||||
|
from fastapi.security.api_key import APIKey, APIKeyCookie, APIKeyHeader, APIKeyQuery
|
||||||
|
|
||||||
|
from {{modelPackage}}.extra_models import TokenModel
|
||||||
|
|
||||||
|
{{#authMethods}}
|
||||||
|
{{#isOAuth}}
|
||||||
|
{{#isPassword}}
|
||||||
|
oauth2_password = OAuth2PasswordBearer(
|
||||||
|
tokenUrl="{{tokenUrl}}",
|
||||||
|
scopes={
|
||||||
|
{{#scopes}}
|
||||||
|
"{{scope}}": "{{description}}",
|
||||||
|
{{/scopes}}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{{/isPassword}}
|
||||||
|
{{#isCode}}
|
||||||
|
oauth2_code = OAuth2AuthorizationCodeBearer(
|
||||||
|
authorizationUrl="{{authorizationUrl}}",
|
||||||
|
tokenUrl="{{tokenUrl}}",
|
||||||
|
refreshUrlUrl="{{refreshUrl}}",
|
||||||
|
scopes={
|
||||||
|
{{#scopes}}
|
||||||
|
"{{scope}}": "{{description}}",
|
||||||
|
{{/scopes}}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{{/isCode}}
|
||||||
|
{{#isImplicit}}
|
||||||
|
oauth2_implicit = OAuth2(
|
||||||
|
flows=OAuthFlows(
|
||||||
|
implicit=OAuthFlowImplicit(
|
||||||
|
authorizationUrl="{{authorizationUrl}}",
|
||||||
|
scopes={
|
||||||
|
{{#scopes}}
|
||||||
|
"{{scope}}": "{{description}}",
|
||||||
|
{{/scopes}}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{{/isImplicit}}
|
||||||
|
|
||||||
|
|
||||||
|
def get_token_{{name}}(
|
||||||
|
security_scopes: SecurityScopes, token: str = Depends(oauth2_{{#isPassword}}password{{/isPassword}}{{#isCode}}code{{/isCode}}{{#isImplicit}}implicit{{/isImplicit}})
|
||||||
|
) -> TokenModel:
|
||||||
|
"""
|
||||||
|
Validate and decode token.
|
||||||
|
|
||||||
|
:param token Token provided by Authorization header
|
||||||
|
:type token: str
|
||||||
|
:return: Decoded token information or None if token is invalid
|
||||||
|
:rtype: TokenModel | None
|
||||||
|
"""
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def validate_scope_{{name}}(
|
||||||
|
required_scopes: SecurityScopes, token_scopes: List[str]
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Validate required scopes are included in token scope
|
||||||
|
|
||||||
|
:param required_scopes Required scope to access called API
|
||||||
|
:type required_scopes: List[str]
|
||||||
|
:param token_scopes Scope present in token
|
||||||
|
:type token_scopes: List[str]
|
||||||
|
:return: True if access to called API is allowed
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
{{/isOAuth}}
|
||||||
|
{{#isApiKey}}
|
||||||
|
|
||||||
|
def get_token_{{name}}(
|
||||||
|
{{#isKeyInHeader}}token_api_key_header: str = Security(
|
||||||
|
APIKeyHeader(name="{{keyParamName}}", auto_error=False)
|
||||||
|
),{{/isKeyInHeader}}{{#isKeyInCookie}}
|
||||||
|
token_api_key_cookie: str = Security(
|
||||||
|
APIKeyCookie(name="{{keyParamName}}", auto_error=False)
|
||||||
|
),{{/isKeyInCookie}}{{#isKeyInQuery}}
|
||||||
|
token_api_key_query: str = Security(
|
||||||
|
APIKeyQuery(name="{{keyParamName}}", auto_error=False)
|
||||||
|
),{{/isKeyInQuery}}
|
||||||
|
) -> TokenModel:
|
||||||
|
"""
|
||||||
|
Check and retrieve authentication information from api_key.
|
||||||
|
|
||||||
|
{{#isKeyInHeader}}:param token_api_key_header API key provided by Authorization[{{keyParamName}}] header{{/isKeyInHeader}}
|
||||||
|
{{#isKeyInCookie}}:param token_api_key_cookie API key provided by Authorization[{{keyParamName}}] cookie{{/isKeyInCookie}}
|
||||||
|
{{#isKeyInQuery}}:param token_api_key_query API key provided by [{{keyParamName}}] query{{/isKeyInQuery}}
|
||||||
|
:type token_api_key_{{#isKeyInHeader}}header{{/isKeyInHeader}}{{#isKeyInCookie}}cookie{{/isKeyInCookie}}{{#isKeyInQuery}}query{{/isKeyInQuery}}: str
|
||||||
|
:return: Information attached to provided api_key or None if api_key is invalid or does not allow access to called API
|
||||||
|
:rtype: TokenModel | None
|
||||||
|
"""
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
{{/isApiKey}}
|
||||||
|
{{#isBasicBasic}}
|
||||||
|
|
||||||
|
basic_auth = HTTPBasic()
|
||||||
|
|
||||||
|
|
||||||
|
def get_token_{{name}}(
|
||||||
|
credentials: HTTPBasicCredentials = Depends(basic_auth)
|
||||||
|
) -> TokenModel:
|
||||||
|
"""
|
||||||
|
Check and retrieve authentication information from basic auth.
|
||||||
|
|
||||||
|
:param credentials Credentials provided by Authorization header
|
||||||
|
:type credentials: HTTPBasicCredentials
|
||||||
|
:rtype: TokenModel | None
|
||||||
|
"""
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
{{/isBasicBasic}}
|
||||||
|
{{#isBasicBearer}}
|
||||||
|
|
||||||
|
bearer_auth = HTTPBearer()
|
||||||
|
|
||||||
|
|
||||||
|
def get_token_{{name}}(credentials: HTTPAuthorizationCredentials = Depends(bearer_auth)) -> TokenModel:
|
||||||
|
"""
|
||||||
|
Check and retrieve authentication information from custom bearer token.
|
||||||
|
|
||||||
|
:param credentials Credentials provided by Authorization header
|
||||||
|
:type credentials: HTTPAuthorizationCredentials
|
||||||
|
:return: Decoded token information or None if token is invalid
|
||||||
|
:rtype: TokenModel | None
|
||||||
|
"""
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
{{/isBasicBearer}}
|
||||||
|
{{/authMethods}}
|
||||||
23
modules/openapi-generator/src/main/resources/python-fastapi/setup_cfg.mustache
vendored
Normal file
23
modules/openapi-generator/src/main/resources/python-fastapi/setup_cfg.mustache
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[metadata]
|
||||||
|
name = {{packageName}}
|
||||||
|
version = {{appVersion}}
|
||||||
|
description = {{appDescription}}
|
||||||
|
long_description = file: README.md
|
||||||
|
keywords = OpenAPI {{appName}}
|
||||||
|
python_requires = >= 3.6.*
|
||||||
|
classifiers =
|
||||||
|
Operating System :: OS Independent
|
||||||
|
Programming Language :: Python :: 3
|
||||||
|
Programming Language :: Python :: 3.6
|
||||||
|
|
||||||
|
[options]
|
||||||
|
install_requires =
|
||||||
|
fastapi[all]
|
||||||
|
setup_requires =
|
||||||
|
setuptools
|
||||||
|
package_dir=
|
||||||
|
=src
|
||||||
|
packages=find_namespace:
|
||||||
|
|
||||||
|
[options.packages.find]
|
||||||
|
where=src
|
||||||
138
samples/server/petstore/python-fastapi/.gitignore
vendored
Normal file
138
samples/server/petstore/python-fastapi/.gitignore
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# OpenAPI Generator Ignore
|
||||||
|
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||||
|
|
||||||
|
# Use this file to prevent files from being overwritten by the generator.
|
||||||
|
# The patterns follow closely to .gitignore or .dockerignore.
|
||||||
|
|
||||||
|
# As an example, the C# client generator defines ApiClient.cs.
|
||||||
|
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||||
|
#ApiClient.cs
|
||||||
|
|
||||||
|
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||||
|
#foo/*/qux
|
||||||
|
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||||
|
|
||||||
|
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||||
|
#foo/**/qux
|
||||||
|
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||||
|
|
||||||
|
# You can also negate patterns with an exclamation (!).
|
||||||
|
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||||
|
#docs/*.md
|
||||||
|
# Then explicitly reverse the ignore rule for a single file:
|
||||||
|
#!docs/README.md
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
.gitignore
|
||||||
|
Dockerfile
|
||||||
|
README.md
|
||||||
|
docker-compose.yaml
|
||||||
|
openapi.yaml
|
||||||
|
pyproject.toml
|
||||||
|
requirements.txt
|
||||||
|
setup.cfg
|
||||||
|
src/openapi_server/apis/__init__.py
|
||||||
|
src/openapi_server/apis/pet_api.py
|
||||||
|
src/openapi_server/apis/store_api.py
|
||||||
|
src/openapi_server/apis/user_api.py
|
||||||
|
src/openapi_server/main.py
|
||||||
|
src/openapi_server/models/__init__.py
|
||||||
|
src/openapi_server/models/api_response.py
|
||||||
|
src/openapi_server/models/category.py
|
||||||
|
src/openapi_server/models/extra_models.py
|
||||||
|
src/openapi_server/models/order.py
|
||||||
|
src/openapi_server/models/pet.py
|
||||||
|
src/openapi_server/models/tag.py
|
||||||
|
src/openapi_server/models/user.py
|
||||||
|
src/openapi_server/security_api.py
|
||||||
|
tests/conftest.py
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
5.2.0-SNAPSHOT
|
||||||
30
samples/server/petstore/python-fastapi/Dockerfile
Normal file
30
samples/server/petstore/python-fastapi/Dockerfile
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
FROM python:3.6 AS builder
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
RUN python3 -m venv /venv
|
||||||
|
ENV PATH="/venv/bin:$PATH"
|
||||||
|
|
||||||
|
RUN pip install --upgrade pip
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN pip install --no-cache-dir .
|
||||||
|
|
||||||
|
|
||||||
|
FROM python:3.6 AS test_runner
|
||||||
|
WORKDIR /tmp
|
||||||
|
COPY --from=builder /venv /venv
|
||||||
|
COPY --from=builder /usr/src/app/tests tests
|
||||||
|
ENV PATH=/venv/bin:$PATH
|
||||||
|
|
||||||
|
# install test dependencies
|
||||||
|
RUN pip install pytest
|
||||||
|
|
||||||
|
# run tests
|
||||||
|
RUN pytest tests
|
||||||
|
|
||||||
|
|
||||||
|
FROM python:3.6 AS service
|
||||||
|
WORKDIR /root/app/site-packages
|
||||||
|
COPY --from=test_runner /venv /venv
|
||||||
|
ENV PATH=/venv/bin:$PATH
|
||||||
29
samples/server/petstore/python-fastapi/README.md
Normal file
29
samples/server/petstore/python-fastapi/README.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# OpenAPI generated FastAPI server
|
||||||
|
|
||||||
|
This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
|
||||||
|
|
||||||
|
- API version: 1.0.0
|
||||||
|
- Build package: org.openapitools.codegen.languages.PythonFastAPIServerCodegen
|
||||||
|
|
||||||
|
## Requirements.
|
||||||
|
|
||||||
|
Python >= 3.6
|
||||||
|
|
||||||
|
## Installation & Usage
|
||||||
|
|
||||||
|
To run the server, please execute the following from the root directory:
|
||||||
|
|
||||||
|
```
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
uvicorn main:app --host 0.0.0.0 --port 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
and open your browser at `http://localhost:8080/docs/` to see the docs.
|
||||||
|
|
||||||
|
## Running with Docker
|
||||||
|
|
||||||
|
To run the server on a Docker container, please execute the following from the root directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up --build
|
||||||
|
```
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
version: '3.6'
|
||||||
|
services:
|
||||||
|
service:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: service
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
command: uvicorn openapi_server.main:app --host 0.0.0.0 --port 8080
|
||||||
843
samples/server/petstore/python-fastapi/openapi.yaml
Normal file
843
samples/server/petstore/python-fastapi/openapi.yaml
Normal file
@@ -0,0 +1,843 @@
|
|||||||
|
openapi: 3.0.0
|
||||||
|
info:
|
||||||
|
description: This is a sample server Petstore server. For this sample, you can use
|
||||||
|
the api key `special-key` to test the authorization filters.
|
||||||
|
license:
|
||||||
|
name: Apache-2.0
|
||||||
|
url: https://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
title: OpenAPI Petstore
|
||||||
|
version: 1.0.0
|
||||||
|
externalDocs:
|
||||||
|
description: Find out more about Swagger
|
||||||
|
url: http://swagger.io
|
||||||
|
servers:
|
||||||
|
- url: http://petstore.swagger.io/v2
|
||||||
|
tags:
|
||||||
|
- description: Everything about your Pets
|
||||||
|
name: pet
|
||||||
|
- description: Access to Petstore orders
|
||||||
|
name: store
|
||||||
|
- description: Operations about user
|
||||||
|
name: user
|
||||||
|
paths:
|
||||||
|
/pet:
|
||||||
|
post:
|
||||||
|
operationId: addPet
|
||||||
|
requestBody:
|
||||||
|
$ref: '#/components/requestBodies/Pet'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
description: successful operation
|
||||||
|
"405":
|
||||||
|
description: Invalid input
|
||||||
|
security:
|
||||||
|
- petstore_auth:
|
||||||
|
- write:pets
|
||||||
|
- read:pets
|
||||||
|
summary: Add a new pet to the store
|
||||||
|
tags:
|
||||||
|
- pet
|
||||||
|
put:
|
||||||
|
operationId: updatePet
|
||||||
|
requestBody:
|
||||||
|
$ref: '#/components/requestBodies/Pet'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
description: successful operation
|
||||||
|
"400":
|
||||||
|
description: Invalid ID supplied
|
||||||
|
"404":
|
||||||
|
description: Pet not found
|
||||||
|
"405":
|
||||||
|
description: Validation exception
|
||||||
|
security:
|
||||||
|
- petstore_auth:
|
||||||
|
- write:pets
|
||||||
|
- read:pets
|
||||||
|
summary: Update an existing pet
|
||||||
|
tags:
|
||||||
|
- pet
|
||||||
|
/pet/findByStatus:
|
||||||
|
get:
|
||||||
|
description: Multiple status values can be provided with comma separated strings
|
||||||
|
operationId: findPetsByStatus
|
||||||
|
parameters:
|
||||||
|
- description: Status values that need to be considered for filter
|
||||||
|
explode: false
|
||||||
|
in: query
|
||||||
|
name: status
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
default: available
|
||||||
|
enum:
|
||||||
|
- available
|
||||||
|
- pending
|
||||||
|
- sold
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
style: form
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
type: array
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
type: array
|
||||||
|
description: successful operation
|
||||||
|
"400":
|
||||||
|
description: Invalid status value
|
||||||
|
security:
|
||||||
|
- petstore_auth:
|
||||||
|
- read:pets
|
||||||
|
summary: Finds Pets by status
|
||||||
|
tags:
|
||||||
|
- pet
|
||||||
|
/pet/findByTags:
|
||||||
|
get:
|
||||||
|
deprecated: true
|
||||||
|
description: Multiple tags can be provided with comma separated strings. Use
|
||||||
|
tag1, tag2, tag3 for testing.
|
||||||
|
operationId: findPetsByTags
|
||||||
|
parameters:
|
||||||
|
- description: Tags to filter by
|
||||||
|
explode: false
|
||||||
|
in: query
|
||||||
|
name: tags
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
style: form
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
type: array
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
type: array
|
||||||
|
description: successful operation
|
||||||
|
"400":
|
||||||
|
description: Invalid tag value
|
||||||
|
security:
|
||||||
|
- petstore_auth:
|
||||||
|
- read:pets
|
||||||
|
summary: Finds Pets by tags
|
||||||
|
tags:
|
||||||
|
- pet
|
||||||
|
/pet/{petId}:
|
||||||
|
delete:
|
||||||
|
operationId: deletePet
|
||||||
|
parameters:
|
||||||
|
- explode: false
|
||||||
|
in: header
|
||||||
|
name: api_key
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
style: simple
|
||||||
|
- description: Pet id to delete
|
||||||
|
explode: false
|
||||||
|
in: path
|
||||||
|
name: petId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
style: simple
|
||||||
|
responses:
|
||||||
|
"400":
|
||||||
|
description: Invalid pet value
|
||||||
|
security:
|
||||||
|
- petstore_auth:
|
||||||
|
- write:pets
|
||||||
|
- read:pets
|
||||||
|
summary: Deletes a pet
|
||||||
|
tags:
|
||||||
|
- pet
|
||||||
|
get:
|
||||||
|
description: Returns a single pet
|
||||||
|
operationId: getPetById
|
||||||
|
parameters:
|
||||||
|
- description: ID of pet to return
|
||||||
|
explode: false
|
||||||
|
in: path
|
||||||
|
name: petId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
style: simple
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
description: successful operation
|
||||||
|
"400":
|
||||||
|
description: Invalid ID supplied
|
||||||
|
"404":
|
||||||
|
description: Pet not found
|
||||||
|
security:
|
||||||
|
- api_key: []
|
||||||
|
summary: Find pet by ID
|
||||||
|
tags:
|
||||||
|
- pet
|
||||||
|
post:
|
||||||
|
operationId: updatePetWithForm
|
||||||
|
parameters:
|
||||||
|
- description: ID of pet that needs to be updated
|
||||||
|
explode: false
|
||||||
|
in: path
|
||||||
|
name: petId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
style: simple
|
||||||
|
requestBody:
|
||||||
|
$ref: '#/components/requestBodies/inline_object'
|
||||||
|
content:
|
||||||
|
application/x-www-form-urlencoded:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Updated name of the pet
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: Updated status of the pet
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
responses:
|
||||||
|
"405":
|
||||||
|
description: Invalid input
|
||||||
|
security:
|
||||||
|
- petstore_auth:
|
||||||
|
- write:pets
|
||||||
|
- read:pets
|
||||||
|
summary: Updates a pet in the store with form data
|
||||||
|
tags:
|
||||||
|
- pet
|
||||||
|
/pet/{petId}/uploadImage:
|
||||||
|
post:
|
||||||
|
operationId: uploadFile
|
||||||
|
parameters:
|
||||||
|
- description: ID of pet to update
|
||||||
|
explode: false
|
||||||
|
in: path
|
||||||
|
name: petId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
style: simple
|
||||||
|
requestBody:
|
||||||
|
$ref: '#/components/requestBodies/inline_object_1'
|
||||||
|
content:
|
||||||
|
multipart/form-data:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
additionalMetadata:
|
||||||
|
description: Additional data to pass to server
|
||||||
|
type: string
|
||||||
|
file:
|
||||||
|
description: file to upload
|
||||||
|
format: binary
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ApiResponse'
|
||||||
|
description: successful operation
|
||||||
|
security:
|
||||||
|
- petstore_auth:
|
||||||
|
- write:pets
|
||||||
|
- read:pets
|
||||||
|
summary: uploads an image
|
||||||
|
tags:
|
||||||
|
- pet
|
||||||
|
/store/inventory:
|
||||||
|
get:
|
||||||
|
description: Returns a map of status codes to quantities
|
||||||
|
operationId: getInventory
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
description: successful operation
|
||||||
|
security:
|
||||||
|
- api_key: []
|
||||||
|
summary: Returns pet inventories by status
|
||||||
|
tags:
|
||||||
|
- store
|
||||||
|
/store/order:
|
||||||
|
post:
|
||||||
|
operationId: placeOrder
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Order'
|
||||||
|
description: order placed for purchasing the pet
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Order'
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Order'
|
||||||
|
description: successful operation
|
||||||
|
"400":
|
||||||
|
description: Invalid Order
|
||||||
|
summary: Place an order for a pet
|
||||||
|
tags:
|
||||||
|
- store
|
||||||
|
/store/order/{orderId}:
|
||||||
|
delete:
|
||||||
|
description: For valid response try integer IDs with value < 1000. Anything
|
||||||
|
above 1000 or nonintegers will generate API errors
|
||||||
|
operationId: deleteOrder
|
||||||
|
parameters:
|
||||||
|
- description: ID of the order that needs to be deleted
|
||||||
|
explode: false
|
||||||
|
in: path
|
||||||
|
name: orderId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
style: simple
|
||||||
|
responses:
|
||||||
|
"400":
|
||||||
|
description: Invalid ID supplied
|
||||||
|
"404":
|
||||||
|
description: Order not found
|
||||||
|
summary: Delete purchase order by ID
|
||||||
|
tags:
|
||||||
|
- store
|
||||||
|
get:
|
||||||
|
description: For valid response try integer IDs with value <= 5 or > 10. Other
|
||||||
|
values will generated exceptions
|
||||||
|
operationId: getOrderById
|
||||||
|
parameters:
|
||||||
|
- description: ID of pet that needs to be fetched
|
||||||
|
explode: false
|
||||||
|
in: path
|
||||||
|
name: orderId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: int64
|
||||||
|
maximum: 5
|
||||||
|
minimum: 1
|
||||||
|
type: integer
|
||||||
|
style: simple
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Order'
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Order'
|
||||||
|
description: successful operation
|
||||||
|
"400":
|
||||||
|
description: Invalid ID supplied
|
||||||
|
"404":
|
||||||
|
description: Order not found
|
||||||
|
summary: Find purchase order by ID
|
||||||
|
tags:
|
||||||
|
- store
|
||||||
|
/user:
|
||||||
|
post:
|
||||||
|
description: This can only be done by the logged in user.
|
||||||
|
operationId: createUser
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
description: Created user object
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
default:
|
||||||
|
description: successful operation
|
||||||
|
security:
|
||||||
|
- api_key: []
|
||||||
|
summary: Create user
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
/user/createWithArray:
|
||||||
|
post:
|
||||||
|
operationId: createUsersWithArrayInput
|
||||||
|
requestBody:
|
||||||
|
$ref: '#/components/requestBodies/UserArray'
|
||||||
|
responses:
|
||||||
|
default:
|
||||||
|
description: successful operation
|
||||||
|
security:
|
||||||
|
- api_key: []
|
||||||
|
summary: Creates list of users with given input array
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
/user/createWithList:
|
||||||
|
post:
|
||||||
|
operationId: createUsersWithListInput
|
||||||
|
requestBody:
|
||||||
|
$ref: '#/components/requestBodies/UserArray'
|
||||||
|
responses:
|
||||||
|
default:
|
||||||
|
description: successful operation
|
||||||
|
security:
|
||||||
|
- api_key: []
|
||||||
|
summary: Creates list of users with given input array
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
/user/login:
|
||||||
|
get:
|
||||||
|
operationId: loginUser
|
||||||
|
parameters:
|
||||||
|
- description: The user name for login
|
||||||
|
explode: true
|
||||||
|
in: query
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
pattern: ^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$
|
||||||
|
type: string
|
||||||
|
style: form
|
||||||
|
- description: The password for login in clear text
|
||||||
|
explode: true
|
||||||
|
in: query
|
||||||
|
name: password
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
style: form
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: successful operation
|
||||||
|
headers:
|
||||||
|
Set-Cookie:
|
||||||
|
description: Cookie authentication key for use with the `api_key` apiKey
|
||||||
|
authentication.
|
||||||
|
explode: false
|
||||||
|
schema:
|
||||||
|
example: AUTH_KEY=abcde12345; Path=/; HttpOnly
|
||||||
|
type: string
|
||||||
|
style: simple
|
||||||
|
X-Rate-Limit:
|
||||||
|
description: calls per hour allowed by the user
|
||||||
|
explode: false
|
||||||
|
schema:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
style: simple
|
||||||
|
X-Expires-After:
|
||||||
|
description: date in UTC when toekn expires
|
||||||
|
explode: false
|
||||||
|
schema:
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
style: simple
|
||||||
|
"400":
|
||||||
|
description: Invalid username/password supplied
|
||||||
|
summary: Logs user into the system
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
/user/logout:
|
||||||
|
get:
|
||||||
|
operationId: logoutUser
|
||||||
|
responses:
|
||||||
|
default:
|
||||||
|
description: successful operation
|
||||||
|
security:
|
||||||
|
- api_key: []
|
||||||
|
summary: Logs out current logged in user session
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
/user/{username}:
|
||||||
|
delete:
|
||||||
|
description: This can only be done by the logged in user.
|
||||||
|
operationId: deleteUser
|
||||||
|
parameters:
|
||||||
|
- description: The name that needs to be deleted
|
||||||
|
explode: false
|
||||||
|
in: path
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
style: simple
|
||||||
|
responses:
|
||||||
|
"400":
|
||||||
|
description: Invalid username supplied
|
||||||
|
"404":
|
||||||
|
description: User not found
|
||||||
|
security:
|
||||||
|
- api_key: []
|
||||||
|
summary: Delete user
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
get:
|
||||||
|
operationId: getUserByName
|
||||||
|
parameters:
|
||||||
|
- description: The name that needs to be fetched. Use user1 for testing.
|
||||||
|
explode: false
|
||||||
|
in: path
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
style: simple
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
description: successful operation
|
||||||
|
"400":
|
||||||
|
description: Invalid username supplied
|
||||||
|
"404":
|
||||||
|
description: User not found
|
||||||
|
summary: Get user by user name
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
put:
|
||||||
|
description: This can only be done by the logged in user.
|
||||||
|
operationId: updateUser
|
||||||
|
parameters:
|
||||||
|
- description: name that need to be deleted
|
||||||
|
explode: false
|
||||||
|
in: path
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
style: simple
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
description: Updated user object
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"400":
|
||||||
|
description: Invalid user supplied
|
||||||
|
"404":
|
||||||
|
description: User not found
|
||||||
|
security:
|
||||||
|
- api_key: []
|
||||||
|
summary: Updated user
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
components:
|
||||||
|
requestBodies:
|
||||||
|
UserArray:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
type: array
|
||||||
|
description: List of user object
|
||||||
|
required: true
|
||||||
|
Pet:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
description: Pet object that needs to be added to the store
|
||||||
|
required: true
|
||||||
|
inline_object:
|
||||||
|
content:
|
||||||
|
application/x-www-form-urlencoded:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/inline_object'
|
||||||
|
inline_object_1:
|
||||||
|
content:
|
||||||
|
multipart/form-data:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/inline_object_1'
|
||||||
|
schemas:
|
||||||
|
Order:
|
||||||
|
description: An order for a pets from the pet store
|
||||||
|
example:
|
||||||
|
petId: 6
|
||||||
|
quantity: 1
|
||||||
|
id: 0
|
||||||
|
shipDate: 2000-01-23T04:56:07.000+00:00
|
||||||
|
complete: false
|
||||||
|
status: placed
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
format: int64
|
||||||
|
title: id
|
||||||
|
type: integer
|
||||||
|
petId:
|
||||||
|
format: int64
|
||||||
|
title: petId
|
||||||
|
type: integer
|
||||||
|
quantity:
|
||||||
|
format: int32
|
||||||
|
title: quantity
|
||||||
|
type: integer
|
||||||
|
shipDate:
|
||||||
|
format: date-time
|
||||||
|
title: shipDate
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: Order Status
|
||||||
|
enum:
|
||||||
|
- placed
|
||||||
|
- approved
|
||||||
|
- delivered
|
||||||
|
title: status
|
||||||
|
type: string
|
||||||
|
complete:
|
||||||
|
default: false
|
||||||
|
title: complete
|
||||||
|
type: boolean
|
||||||
|
title: Pet Order
|
||||||
|
type: object
|
||||||
|
xml:
|
||||||
|
name: Order
|
||||||
|
Category:
|
||||||
|
description: A category for a pet
|
||||||
|
example:
|
||||||
|
name: name
|
||||||
|
id: 6
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
format: int64
|
||||||
|
title: id
|
||||||
|
type: integer
|
||||||
|
name:
|
||||||
|
pattern: ^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$
|
||||||
|
title: name
|
||||||
|
type: string
|
||||||
|
title: Pet category
|
||||||
|
type: object
|
||||||
|
xml:
|
||||||
|
name: Category
|
||||||
|
User:
|
||||||
|
description: A User who is purchasing from the pet store
|
||||||
|
example:
|
||||||
|
firstName: firstName
|
||||||
|
lastName: lastName
|
||||||
|
password: password
|
||||||
|
userStatus: 6
|
||||||
|
phone: phone
|
||||||
|
id: 0
|
||||||
|
email: email
|
||||||
|
username: username
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
firstName:
|
||||||
|
type: string
|
||||||
|
lastName:
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
phone:
|
||||||
|
type: string
|
||||||
|
userStatus:
|
||||||
|
description: User Status
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
title: a User
|
||||||
|
type: object
|
||||||
|
xml:
|
||||||
|
name: User
|
||||||
|
Tag:
|
||||||
|
description: A tag for a pet
|
||||||
|
example:
|
||||||
|
name: name
|
||||||
|
id: 1
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
format: int64
|
||||||
|
title: id
|
||||||
|
type: integer
|
||||||
|
name:
|
||||||
|
title: name
|
||||||
|
type: string
|
||||||
|
title: Pet Tag
|
||||||
|
type: object
|
||||||
|
xml:
|
||||||
|
name: Tag
|
||||||
|
Pet:
|
||||||
|
description: A pet for sale in the pet store
|
||||||
|
example:
|
||||||
|
photoUrls:
|
||||||
|
- photoUrls
|
||||||
|
- photoUrls
|
||||||
|
name: doggie
|
||||||
|
id: 0
|
||||||
|
category:
|
||||||
|
name: name
|
||||||
|
id: 6
|
||||||
|
tags:
|
||||||
|
- name: name
|
||||||
|
id: 1
|
||||||
|
- name: name
|
||||||
|
id: 1
|
||||||
|
status: available
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
format: int64
|
||||||
|
title: id
|
||||||
|
type: integer
|
||||||
|
category:
|
||||||
|
$ref: '#/components/schemas/Category'
|
||||||
|
name:
|
||||||
|
example: doggie
|
||||||
|
title: name
|
||||||
|
type: string
|
||||||
|
photoUrls:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
title: photoUrls
|
||||||
|
type: array
|
||||||
|
xml:
|
||||||
|
name: photoUrl
|
||||||
|
wrapped: true
|
||||||
|
tags:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Tag'
|
||||||
|
title: tags
|
||||||
|
type: array
|
||||||
|
xml:
|
||||||
|
name: tag
|
||||||
|
wrapped: true
|
||||||
|
status:
|
||||||
|
description: pet status in the store
|
||||||
|
enum:
|
||||||
|
- available
|
||||||
|
- pending
|
||||||
|
- sold
|
||||||
|
title: status
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- photoUrls
|
||||||
|
title: a Pet
|
||||||
|
type: object
|
||||||
|
xml:
|
||||||
|
name: Pet
|
||||||
|
ApiResponse:
|
||||||
|
description: Describes the result of uploading an image resource
|
||||||
|
example:
|
||||||
|
code: 0
|
||||||
|
type: type
|
||||||
|
message: message
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
format: int32
|
||||||
|
title: code
|
||||||
|
type: integer
|
||||||
|
type:
|
||||||
|
title: type
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
title: message
|
||||||
|
type: string
|
||||||
|
title: An uploaded response
|
||||||
|
type: object
|
||||||
|
inline_object:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Updated name of the pet
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: Updated status of the pet
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
inline_object_1:
|
||||||
|
properties:
|
||||||
|
additionalMetadata:
|
||||||
|
description: Additional data to pass to server
|
||||||
|
type: string
|
||||||
|
file:
|
||||||
|
description: file to upload
|
||||||
|
format: binary
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
securitySchemes:
|
||||||
|
petstore_auth:
|
||||||
|
flows:
|
||||||
|
implicit:
|
||||||
|
authorizationUrl: http://petstore.swagger.io/api/oauth/dialog
|
||||||
|
scopes:
|
||||||
|
write:pets: modify pets in your account
|
||||||
|
read:pets: read your pets
|
||||||
|
type: oauth2
|
||||||
|
x-tokenInfoFunc: .security_controller_.info_from_petstore_auth
|
||||||
|
x-scopeValidateFunc: .security_controller_.validate_scope_petstore_auth
|
||||||
|
api_key:
|
||||||
|
in: header
|
||||||
|
name: api_key
|
||||||
|
type: apiKey
|
||||||
|
x-apikeyInfoFunc: .security_controller_.info_from_api_key
|
||||||
30
samples/server/petstore/python-fastapi/pyproject.toml
Normal file
30
samples/server/petstore/python-fastapi/pyproject.toml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[tool.black]
|
||||||
|
line-length = 88
|
||||||
|
exclude = '''
|
||||||
|
(
|
||||||
|
/(
|
||||||
|
\.eggs # exclude a few common directories in the
|
||||||
|
| \.git # root of the project
|
||||||
|
| \.hg
|
||||||
|
| \.mypy_cache
|
||||||
|
| \.tox
|
||||||
|
| \.venv
|
||||||
|
| _build
|
||||||
|
| buck-out
|
||||||
|
| build
|
||||||
|
| dist
|
||||||
|
)/
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
profile = "black"
|
||||||
|
skip = [
|
||||||
|
'.eggs', '.git', '.hg', '.mypy_cache', '.nox', '.pants.d', '.tox',
|
||||||
|
'.venv', '_build', 'buck-out', 'build', 'dist', 'node_modules', 'venv',
|
||||||
|
]
|
||||||
|
skip_gitignore = true
|
||||||
36
samples/server/petstore/python-fastapi/requirements.txt
Normal file
36
samples/server/petstore/python-fastapi/requirements.txt
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
aiofiles==0.5.0
|
||||||
|
aniso8601==7.0.0
|
||||||
|
async-exit-stack==1.0.1
|
||||||
|
async-generator==1.10
|
||||||
|
certifi==2020.12.5
|
||||||
|
chardet==4.0.0
|
||||||
|
click==7.1.2
|
||||||
|
dnspython==2.1.0
|
||||||
|
email-validator==1.1.2
|
||||||
|
fastapi==0.65.1
|
||||||
|
graphene==2.1.8
|
||||||
|
graphql-core==2.3.2
|
||||||
|
graphql-relay==2.0.1
|
||||||
|
h11==0.12.0
|
||||||
|
httptools==0.1.2
|
||||||
|
idna==2.10
|
||||||
|
itsdangerous==1.1.0
|
||||||
|
Jinja2==2.11.3
|
||||||
|
MarkupSafe==2.0.1
|
||||||
|
orjson==3.5.2
|
||||||
|
promise==2.3
|
||||||
|
pydantic==1.8.2
|
||||||
|
python-dotenv==0.17.1
|
||||||
|
python-multipart==0.0.5
|
||||||
|
PyYAML==5.4.1
|
||||||
|
requests==2.25.1
|
||||||
|
Rx==1.6.1
|
||||||
|
six==1.16.0
|
||||||
|
starlette==0.14.2
|
||||||
|
typing-extensions==3.10.0.0
|
||||||
|
ujson==4.0.2
|
||||||
|
urllib3==1.26.4
|
||||||
|
uvicorn==0.13.4
|
||||||
|
uvloop==0.14.0
|
||||||
|
watchgod==0.7
|
||||||
|
websockets==8.1
|
||||||
23
samples/server/petstore/python-fastapi/setup.cfg
Normal file
23
samples/server/petstore/python-fastapi/setup.cfg
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[metadata]
|
||||||
|
name = openapi_server
|
||||||
|
version = 1.0.0
|
||||||
|
description = This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
|
||||||
|
long_description = file: README.md
|
||||||
|
keywords = OpenAPI OpenAPI Petstore
|
||||||
|
python_requires = >= 3.6.*
|
||||||
|
classifiers =
|
||||||
|
Operating System :: OS Independent
|
||||||
|
Programming Language :: Python :: 3
|
||||||
|
Programming Language :: Python :: 3.6
|
||||||
|
|
||||||
|
[options]
|
||||||
|
install_requires =
|
||||||
|
fastapi[all]
|
||||||
|
setup_requires =
|
||||||
|
setuptools
|
||||||
|
package_dir=
|
||||||
|
=src
|
||||||
|
packages=find_namespace:
|
||||||
|
|
||||||
|
[options.packages.find]
|
||||||
|
where=src
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
from fastapi import (
|
||||||
|
APIRouter,
|
||||||
|
Body,
|
||||||
|
Cookie,
|
||||||
|
Depends,
|
||||||
|
Form,
|
||||||
|
Header,
|
||||||
|
Path,
|
||||||
|
Query,
|
||||||
|
Response,
|
||||||
|
Security,
|
||||||
|
status,
|
||||||
|
)
|
||||||
|
|
||||||
|
from openapi_server.models.extra_models import TokenModel
|
||||||
|
from openapi_server.models.api_response import ApiResponse
|
||||||
|
from openapi_server.models.pet import Pet
|
||||||
|
from openapi_server.security_api import get_token_petstore_auth, get_token_api_key
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/pet",
|
||||||
|
responses={
|
||||||
|
200: {"model": Pet, "description": "successful operation"},
|
||||||
|
405: {"description": "Invalid input"},
|
||||||
|
},
|
||||||
|
tags=["pet"],
|
||||||
|
summary="Add a new pet to the store",
|
||||||
|
)
|
||||||
|
async def add_pet(
|
||||||
|
pet: Pet = Body(None, description="Pet object that needs to be added to the store")
|
||||||
|
,
|
||||||
|
token_petstore_auth: TokenModel = Security(
|
||||||
|
get_token_petstore_auth, scopes=["write:pets", "read:pets"]
|
||||||
|
),
|
||||||
|
) -> Pet: # noqa: E501
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete(
|
||||||
|
"/pet/{petId}",
|
||||||
|
responses={
|
||||||
|
400: {"description": "Invalid pet value"},
|
||||||
|
},
|
||||||
|
tags=["pet"],
|
||||||
|
summary="Deletes a pet",
|
||||||
|
)
|
||||||
|
async def delete_pet(
|
||||||
|
petId: int = Path(None, description="Pet id to delete")
|
||||||
|
,
|
||||||
|
api_key: str = Header(None, description="")
|
||||||
|
,
|
||||||
|
token_petstore_auth: TokenModel = Security(
|
||||||
|
get_token_petstore_auth, scopes=["write:pets", "read:pets"]
|
||||||
|
),
|
||||||
|
) -> None: # noqa: E501
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/pet/findByStatus",
|
||||||
|
responses={
|
||||||
|
200: {"model": List[Pet], "description": "successful operation"},
|
||||||
|
400: {"description": "Invalid status value"},
|
||||||
|
},
|
||||||
|
tags=["pet"],
|
||||||
|
summary="Finds Pets by status",
|
||||||
|
)
|
||||||
|
async def find_pets_by_status(
|
||||||
|
status: List[str] = Query(None, description="Status values that need to be considered for filter")
|
||||||
|
,
|
||||||
|
token_petstore_auth: TokenModel = Security(
|
||||||
|
get_token_petstore_auth, scopes=["read:pets"]
|
||||||
|
),
|
||||||
|
) -> List[Pet]: # noqa: E501
|
||||||
|
"""Multiple status values can be provided with comma separated strings"""
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/pet/findByTags",
|
||||||
|
responses={
|
||||||
|
200: {"model": List[Pet], "description": "successful operation"},
|
||||||
|
400: {"description": "Invalid tag value"},
|
||||||
|
},
|
||||||
|
tags=["pet"],
|
||||||
|
summary="Finds Pets by tags",
|
||||||
|
)
|
||||||
|
async def find_pets_by_tags(
|
||||||
|
tags: List[str] = Query(None, description="Tags to filter by")
|
||||||
|
,
|
||||||
|
token_petstore_auth: TokenModel = Security(
|
||||||
|
get_token_petstore_auth, scopes=["read:pets"]
|
||||||
|
),
|
||||||
|
) -> List[Pet]: # noqa: E501
|
||||||
|
"""Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing."""
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/pet/{petId}",
|
||||||
|
responses={
|
||||||
|
200: {"model": Pet, "description": "successful operation"},
|
||||||
|
400: {"description": "Invalid ID supplied"},
|
||||||
|
404: {"description": "Pet not found"},
|
||||||
|
},
|
||||||
|
tags=["pet"],
|
||||||
|
summary="Find pet by ID",
|
||||||
|
)
|
||||||
|
async def get_pet_by_id(
|
||||||
|
petId: int = Path(None, description="ID of pet to return")
|
||||||
|
,
|
||||||
|
token_api_key: TokenModel = Security(
|
||||||
|
get_token_api_key
|
||||||
|
),
|
||||||
|
) -> Pet: # noqa: E501
|
||||||
|
"""Returns a single pet"""
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.put(
|
||||||
|
"/pet",
|
||||||
|
responses={
|
||||||
|
200: {"model": Pet, "description": "successful operation"},
|
||||||
|
400: {"description": "Invalid ID supplied"},
|
||||||
|
404: {"description": "Pet not found"},
|
||||||
|
405: {"description": "Validation exception"},
|
||||||
|
},
|
||||||
|
tags=["pet"],
|
||||||
|
summary="Update an existing pet",
|
||||||
|
)
|
||||||
|
async def update_pet(
|
||||||
|
pet: Pet = Body(None, description="Pet object that needs to be added to the store")
|
||||||
|
,
|
||||||
|
token_petstore_auth: TokenModel = Security(
|
||||||
|
get_token_petstore_auth, scopes=["write:pets", "read:pets"]
|
||||||
|
),
|
||||||
|
) -> Pet: # noqa: E501
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/pet/{petId}",
|
||||||
|
responses={
|
||||||
|
405: {"description": "Invalid input"},
|
||||||
|
},
|
||||||
|
tags=["pet"],
|
||||||
|
summary="Updates a pet in the store with form data",
|
||||||
|
)
|
||||||
|
async def update_pet_with_form(
|
||||||
|
petId: int = Path(None, description="ID of pet that needs to be updated")
|
||||||
|
,
|
||||||
|
name: str = Form(None, description="Updated name of the pet")
|
||||||
|
,
|
||||||
|
status: str = Form(None, description="Updated status of the pet")
|
||||||
|
,
|
||||||
|
token_petstore_auth: TokenModel = Security(
|
||||||
|
get_token_petstore_auth, scopes=["write:pets", "read:pets"]
|
||||||
|
),
|
||||||
|
) -> None: # noqa: E501
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/pet/{petId}/uploadImage",
|
||||||
|
responses={
|
||||||
|
200: {"model": ApiResponse, "description": "successful operation"},
|
||||||
|
},
|
||||||
|
tags=["pet"],
|
||||||
|
summary="uploads an image",
|
||||||
|
)
|
||||||
|
async def upload_file(
|
||||||
|
petId: int = Path(None, description="ID of pet to update")
|
||||||
|
,
|
||||||
|
additional_metadata: str = Form(None, description="Additional data to pass to server")
|
||||||
|
,
|
||||||
|
file: str = Form(None, description="file to upload")
|
||||||
|
,
|
||||||
|
token_petstore_auth: TokenModel = Security(
|
||||||
|
get_token_petstore_auth, scopes=["write:pets", "read:pets"]
|
||||||
|
),
|
||||||
|
) -> ApiResponse: # noqa: E501
|
||||||
|
...
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
from fastapi import (
|
||||||
|
APIRouter,
|
||||||
|
Body,
|
||||||
|
Cookie,
|
||||||
|
Depends,
|
||||||
|
Form,
|
||||||
|
Header,
|
||||||
|
Path,
|
||||||
|
Query,
|
||||||
|
Response,
|
||||||
|
Security,
|
||||||
|
status,
|
||||||
|
)
|
||||||
|
|
||||||
|
from openapi_server.models.extra_models import TokenModel
|
||||||
|
from openapi_server.models.order import Order
|
||||||
|
from openapi_server.security_api import get_token_api_key
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete(
|
||||||
|
"/store/order/{orderId}",
|
||||||
|
responses={
|
||||||
|
400: {"description": "Invalid ID supplied"},
|
||||||
|
404: {"description": "Order not found"},
|
||||||
|
},
|
||||||
|
tags=["store"],
|
||||||
|
summary="Delete purchase order by ID",
|
||||||
|
)
|
||||||
|
async def delete_order(
|
||||||
|
orderId: str = Path(None, description="ID of the order that needs to be deleted")
|
||||||
|
,
|
||||||
|
) -> None: # noqa: E501
|
||||||
|
"""For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors"""
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/store/inventory",
|
||||||
|
responses={
|
||||||
|
200: {"model": Dict[str, int], "description": "successful operation"},
|
||||||
|
},
|
||||||
|
tags=["store"],
|
||||||
|
summary="Returns pet inventories by status",
|
||||||
|
)
|
||||||
|
async def get_inventory(
|
||||||
|
token_api_key: TokenModel = Security(
|
||||||
|
get_token_api_key
|
||||||
|
),
|
||||||
|
) -> Dict[str, int]: # noqa: E501
|
||||||
|
"""Returns a map of status codes to quantities"""
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/store/order/{orderId}",
|
||||||
|
responses={
|
||||||
|
200: {"model": Order, "description": "successful operation"},
|
||||||
|
400: {"description": "Invalid ID supplied"},
|
||||||
|
404: {"description": "Order not found"},
|
||||||
|
},
|
||||||
|
tags=["store"],
|
||||||
|
summary="Find purchase order by ID",
|
||||||
|
)
|
||||||
|
async def get_order_by_id(
|
||||||
|
orderId: int = Path(None, description="ID of pet that needs to be fetched")
|
||||||
|
,
|
||||||
|
) -> Order: # noqa: E501
|
||||||
|
"""For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions"""
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/store/order",
|
||||||
|
responses={
|
||||||
|
200: {"model": Order, "description": "successful operation"},
|
||||||
|
400: {"description": "Invalid Order"},
|
||||||
|
},
|
||||||
|
tags=["store"],
|
||||||
|
summary="Place an order for a pet",
|
||||||
|
)
|
||||||
|
async def place_order(
|
||||||
|
order: Order = Body(None, description="order placed for purchasing the pet")
|
||||||
|
,
|
||||||
|
) -> Order: # noqa: E501
|
||||||
|
...
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
from fastapi import (
|
||||||
|
APIRouter,
|
||||||
|
Body,
|
||||||
|
Cookie,
|
||||||
|
Depends,
|
||||||
|
Form,
|
||||||
|
Header,
|
||||||
|
Path,
|
||||||
|
Query,
|
||||||
|
Response,
|
||||||
|
Security,
|
||||||
|
status,
|
||||||
|
)
|
||||||
|
|
||||||
|
from openapi_server.models.extra_models import TokenModel
|
||||||
|
from openapi_server.models.user import User
|
||||||
|
from openapi_server.security_api import get_token_api_key
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/user",
|
||||||
|
responses={
|
||||||
|
200: {"description": "successful operation"},
|
||||||
|
},
|
||||||
|
tags=["user"],
|
||||||
|
summary="Create user",
|
||||||
|
)
|
||||||
|
async def create_user(
|
||||||
|
user: User = Body(None, description="Created user object")
|
||||||
|
,
|
||||||
|
token_api_key: TokenModel = Security(
|
||||||
|
get_token_api_key
|
||||||
|
),
|
||||||
|
) -> None: # noqa: E501
|
||||||
|
"""This can only be done by the logged in user."""
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/user/createWithArray",
|
||||||
|
responses={
|
||||||
|
200: {"description": "successful operation"},
|
||||||
|
},
|
||||||
|
tags=["user"],
|
||||||
|
summary="Creates list of users with given input array",
|
||||||
|
)
|
||||||
|
async def create_users_with_array_input(
|
||||||
|
user: List[User] = Body(None, description="List of user object")
|
||||||
|
,
|
||||||
|
token_api_key: TokenModel = Security(
|
||||||
|
get_token_api_key
|
||||||
|
),
|
||||||
|
) -> None: # noqa: E501
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/user/createWithList",
|
||||||
|
responses={
|
||||||
|
200: {"description": "successful operation"},
|
||||||
|
},
|
||||||
|
tags=["user"],
|
||||||
|
summary="Creates list of users with given input array",
|
||||||
|
)
|
||||||
|
async def create_users_with_list_input(
|
||||||
|
user: List[User] = Body(None, description="List of user object")
|
||||||
|
,
|
||||||
|
token_api_key: TokenModel = Security(
|
||||||
|
get_token_api_key
|
||||||
|
),
|
||||||
|
) -> None: # noqa: E501
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete(
|
||||||
|
"/user/{username}",
|
||||||
|
responses={
|
||||||
|
400: {"description": "Invalid username supplied"},
|
||||||
|
404: {"description": "User not found"},
|
||||||
|
},
|
||||||
|
tags=["user"],
|
||||||
|
summary="Delete user",
|
||||||
|
)
|
||||||
|
async def delete_user(
|
||||||
|
username: str = Path(None, description="The name that needs to be deleted")
|
||||||
|
,
|
||||||
|
token_api_key: TokenModel = Security(
|
||||||
|
get_token_api_key
|
||||||
|
),
|
||||||
|
) -> None: # noqa: E501
|
||||||
|
"""This can only be done by the logged in user."""
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/user/{username}",
|
||||||
|
responses={
|
||||||
|
200: {"model": User, "description": "successful operation"},
|
||||||
|
400: {"description": "Invalid username supplied"},
|
||||||
|
404: {"description": "User not found"},
|
||||||
|
},
|
||||||
|
tags=["user"],
|
||||||
|
summary="Get user by user name",
|
||||||
|
)
|
||||||
|
async def get_user_by_name(
|
||||||
|
username: str = Path(None, description="The name that needs to be fetched. Use user1 for testing.")
|
||||||
|
,
|
||||||
|
) -> User: # noqa: E501
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/user/login",
|
||||||
|
responses={
|
||||||
|
200: {"model": str, "description": "successful operation"},
|
||||||
|
400: {"description": "Invalid username/password supplied"},
|
||||||
|
},
|
||||||
|
tags=["user"],
|
||||||
|
summary="Logs user into the system",
|
||||||
|
)
|
||||||
|
async def login_user(
|
||||||
|
username: str = Query(None, description="The user name for login")
|
||||||
|
,
|
||||||
|
password: str = Query(None, description="The password for login in clear text")
|
||||||
|
,
|
||||||
|
) -> str: # noqa: E501
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/user/logout",
|
||||||
|
responses={
|
||||||
|
200: {"description": "successful operation"},
|
||||||
|
},
|
||||||
|
tags=["user"],
|
||||||
|
summary="Logs out current logged in user session",
|
||||||
|
)
|
||||||
|
async def logout_user(
|
||||||
|
token_api_key: TokenModel = Security(
|
||||||
|
get_token_api_key
|
||||||
|
),
|
||||||
|
) -> None: # noqa: E501
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@router.put(
|
||||||
|
"/user/{username}",
|
||||||
|
responses={
|
||||||
|
400: {"description": "Invalid user supplied"},
|
||||||
|
404: {"description": "User not found"},
|
||||||
|
},
|
||||||
|
tags=["user"],
|
||||||
|
summary="Updated user",
|
||||||
|
)
|
||||||
|
async def update_user(
|
||||||
|
username: str = Path(None, description="name that need to be deleted")
|
||||||
|
,
|
||||||
|
user: User = Body(None, description="Updated user object")
|
||||||
|
,
|
||||||
|
token_api_key: TokenModel = Security(
|
||||||
|
get_token_api_key
|
||||||
|
),
|
||||||
|
) -> None: # noqa: E501
|
||||||
|
"""This can only be done by the logged in user."""
|
||||||
|
...
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
"""
|
||||||
|
OpenAPI Petstore
|
||||||
|
|
||||||
|
This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
|
||||||
|
|
||||||
|
The version of the OpenAPI document: 1.0.0
|
||||||
|
Generated by: https://openapi-generator.tech
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
from openapi_server.apis.pet_api import router as PetApiRouter
|
||||||
|
from openapi_server.apis.store_api import router as StoreApiRouter
|
||||||
|
from openapi_server.apis.user_api import router as UserApiRouter
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
title="OpenAPI Petstore",
|
||||||
|
description="This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.",
|
||||||
|
version="1.0.0",
|
||||||
|
)
|
||||||
|
|
||||||
|
app.include_router(PetApiRouter)
|
||||||
|
app.include_router(StoreApiRouter)
|
||||||
|
app.include_router(UserApiRouter)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, EmailStr, validator
|
||||||
|
|
||||||
|
|
||||||
|
class ApiResponse(BaseModel):
|
||||||
|
"""NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
|
||||||
|
Do not edit the class manually.
|
||||||
|
|
||||||
|
ApiResponse - a model defined in OpenAPI
|
||||||
|
|
||||||
|
code: The code of this ApiResponse [Optional].
|
||||||
|
type: The type of this ApiResponse [Optional].
|
||||||
|
message: The message of this ApiResponse [Optional].
|
||||||
|
"""
|
||||||
|
|
||||||
|
code: Optional[int] = None
|
||||||
|
type: Optional[str] = None
|
||||||
|
message: Optional[str] = None
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, EmailStr, validator
|
||||||
|
|
||||||
|
|
||||||
|
class Category(BaseModel):
|
||||||
|
"""NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
|
||||||
|
Do not edit the class manually.
|
||||||
|
|
||||||
|
Category - a model defined in OpenAPI
|
||||||
|
|
||||||
|
id: The id of this Category [Optional].
|
||||||
|
name: The name of this Category [Optional].
|
||||||
|
"""
|
||||||
|
|
||||||
|
id: Optional[int] = None
|
||||||
|
name: Optional[str] = None
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
class TokenModel(BaseModel):
|
||||||
|
"""Defines a token model."""
|
||||||
|
|
||||||
|
sub: str
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, EmailStr, validator
|
||||||
|
|
||||||
|
|
||||||
|
class Order(BaseModel):
|
||||||
|
"""NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
|
||||||
|
Do not edit the class manually.
|
||||||
|
|
||||||
|
Order - a model defined in OpenAPI
|
||||||
|
|
||||||
|
id: The id of this Order [Optional].
|
||||||
|
pet_id: The pet_id of this Order [Optional].
|
||||||
|
quantity: The quantity of this Order [Optional].
|
||||||
|
ship_date: The ship_date of this Order [Optional].
|
||||||
|
status: The status of this Order [Optional].
|
||||||
|
complete: The complete of this Order [Optional].
|
||||||
|
"""
|
||||||
|
|
||||||
|
id: Optional[int] = None
|
||||||
|
pet_id: Optional[int] = None
|
||||||
|
quantity: Optional[int] = None
|
||||||
|
ship_date: Optional[datetime] = None
|
||||||
|
status: Optional[str] = None
|
||||||
|
complete: Optional[bool] = None
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, EmailStr, validator
|
||||||
|
from openapi_server.models.category import Category
|
||||||
|
from openapi_server.models.tag import Tag
|
||||||
|
|
||||||
|
|
||||||
|
class Pet(BaseModel):
|
||||||
|
"""NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
|
||||||
|
Do not edit the class manually.
|
||||||
|
|
||||||
|
Pet - a model defined in OpenAPI
|
||||||
|
|
||||||
|
id: The id of this Pet [Optional].
|
||||||
|
category: The category of this Pet [Optional].
|
||||||
|
name: The name of this Pet.
|
||||||
|
photo_urls: The photo_urls of this Pet.
|
||||||
|
tags: The tags of this Pet [Optional].
|
||||||
|
status: The status of this Pet [Optional].
|
||||||
|
"""
|
||||||
|
|
||||||
|
id: Optional[int] = None
|
||||||
|
category: Optional[Category] = None
|
||||||
|
name: str
|
||||||
|
photo_urls: List[str]
|
||||||
|
tags: Optional[List[Tag]] = None
|
||||||
|
status: Optional[str] = None
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, EmailStr, validator
|
||||||
|
|
||||||
|
|
||||||
|
class Tag(BaseModel):
|
||||||
|
"""NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
|
||||||
|
Do not edit the class manually.
|
||||||
|
|
||||||
|
Tag - a model defined in OpenAPI
|
||||||
|
|
||||||
|
id: The id of this Tag [Optional].
|
||||||
|
name: The name of this Tag [Optional].
|
||||||
|
"""
|
||||||
|
|
||||||
|
id: Optional[int] = None
|
||||||
|
name: Optional[str] = None
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, EmailStr, validator
|
||||||
|
|
||||||
|
|
||||||
|
class User(BaseModel):
|
||||||
|
"""NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
|
||||||
|
Do not edit the class manually.
|
||||||
|
|
||||||
|
User - a model defined in OpenAPI
|
||||||
|
|
||||||
|
id: The id of this User [Optional].
|
||||||
|
username: The username of this User [Optional].
|
||||||
|
first_name: The first_name of this User [Optional].
|
||||||
|
last_name: The last_name of this User [Optional].
|
||||||
|
email: The email of this User [Optional].
|
||||||
|
password: The password of this User [Optional].
|
||||||
|
phone: The phone of this User [Optional].
|
||||||
|
user_status: The user_status of this User [Optional].
|
||||||
|
"""
|
||||||
|
|
||||||
|
id: Optional[int] = None
|
||||||
|
username: Optional[str] = None
|
||||||
|
first_name: Optional[str] = None
|
||||||
|
last_name: Optional[str] = None
|
||||||
|
email: Optional[str] = None
|
||||||
|
password: Optional[str] = None
|
||||||
|
phone: Optional[str] = None
|
||||||
|
user_status: Optional[int] = None
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, Response, Security, status
|
||||||
|
from fastapi.openapi.models import OAuthFlowImplicit, OAuthFlows
|
||||||
|
from fastapi.security import (
|
||||||
|
HTTPAuthorizationCredentials,
|
||||||
|
HTTPBasic,
|
||||||
|
HTTPBasicCredentials,
|
||||||
|
HTTPBearer,
|
||||||
|
OAuth2,
|
||||||
|
OAuth2AuthorizationCodeBearer,
|
||||||
|
OAuth2PasswordBearer,
|
||||||
|
SecurityScopes,
|
||||||
|
)
|
||||||
|
from fastapi.security.api_key import APIKey, APIKeyCookie, APIKeyHeader, APIKeyQuery
|
||||||
|
|
||||||
|
from openapi_server.models.extra_models import TokenModel
|
||||||
|
|
||||||
|
|
||||||
|
def get_token_api_key(
|
||||||
|
token_api_key_header: str = Security(
|
||||||
|
APIKeyHeader(name="api_key", auto_error=False)
|
||||||
|
),
|
||||||
|
) -> TokenModel:
|
||||||
|
"""
|
||||||
|
Check and retrieve authentication information from api_key.
|
||||||
|
|
||||||
|
:param token_api_key_header API key provided by Authorization[api_key] header
|
||||||
|
|
||||||
|
|
||||||
|
:type token_api_key_header: str
|
||||||
|
:return: Information attached to provided api_key or None if api_key is invalid or does not allow access to called API
|
||||||
|
:rtype: TokenModel | None
|
||||||
|
"""
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
oauth2_implicit = OAuth2(
|
||||||
|
flows=OAuthFlows(
|
||||||
|
implicit=OAuthFlowImplicit(
|
||||||
|
authorizationUrl="http://petstore.swagger.io/api/oauth/dialog",
|
||||||
|
scopes={
|
||||||
|
"write:pets": "modify pets in your account",
|
||||||
|
"read:pets": "read your pets",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_token_petstore_auth(
|
||||||
|
security_scopes: SecurityScopes, token: str = Depends(oauth2_implicit)
|
||||||
|
) -> TokenModel:
|
||||||
|
"""
|
||||||
|
Validate and decode token.
|
||||||
|
|
||||||
|
:param token Token provided by Authorization header
|
||||||
|
:type token: str
|
||||||
|
:return: Decoded token information or None if token is invalid
|
||||||
|
:rtype: TokenModel | None
|
||||||
|
"""
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def validate_scope_petstore_auth(
|
||||||
|
required_scopes: SecurityScopes, token_scopes: List[str]
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Validate required scopes are included in token scope
|
||||||
|
|
||||||
|
:param required_scopes Required scope to access called API
|
||||||
|
:type required_scopes: List[str]
|
||||||
|
:param token_scopes Scope present in token
|
||||||
|
:type token_scopes: List[str]
|
||||||
|
:return: True if access to called API is allowed
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
20
samples/server/petstore/python-fastapi/tests/conftest.py
Normal file
20
samples/server/petstore/python-fastapi/tests/conftest.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import contextlib
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
from openapi_server.main import app as application
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def app() -> FastAPI:
|
||||||
|
application.dependency_overrides = {}
|
||||||
|
|
||||||
|
return application
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def client(app) -> TestClient:
|
||||||
|
return TestClient(app)
|
||||||
165
samples/server/petstore/python-fastapi/tests/test_pet_api.py
Normal file
165
samples/server/petstore/python-fastapi/tests/test_pet_api.py
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from openapi_server.models.api_response import ApiResponse
|
||||||
|
from openapi_server.models.pet import Pet
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_pet(client: TestClient):
|
||||||
|
"""Test case for add_pet
|
||||||
|
|
||||||
|
Add a new pet to the store
|
||||||
|
"""
|
||||||
|
pet = {"photo_urls":["photoUrls","photoUrls"],"name":"doggie","id":0,"category":{"name":"name","id":6},"tags":[{"name":"name","id":1},{"name":"name","id":1}],"status":"available"}
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'POST',
|
||||||
|
'/pet',
|
||||||
|
headers=headers,
|
||||||
|
json=pet,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete_pet(client: TestClient):
|
||||||
|
"""Test case for delete_pet
|
||||||
|
|
||||||
|
Deletes a pet
|
||||||
|
"""
|
||||||
|
headers = {
|
||||||
|
'api_key': 'api_key_example',
|
||||||
|
'Authorization': 'Bearer special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'DELETE',
|
||||||
|
'/pet/{petId}'.format(petId=56),
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_pets_by_status(client: TestClient):
|
||||||
|
"""Test case for find_pets_by_status
|
||||||
|
|
||||||
|
Finds Pets by status
|
||||||
|
"""
|
||||||
|
params = [("status", ['status_example'])]
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'GET',
|
||||||
|
'/pet/findByStatus',
|
||||||
|
headers=headers,
|
||||||
|
params=params,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_pets_by_tags(client: TestClient):
|
||||||
|
"""Test case for find_pets_by_tags
|
||||||
|
|
||||||
|
Finds Pets by tags
|
||||||
|
"""
|
||||||
|
params = [("tags", ['tags_example'])]
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'GET',
|
||||||
|
'/pet/findByTags',
|
||||||
|
headers=headers,
|
||||||
|
params=params,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_pet_by_id(client: TestClient):
|
||||||
|
"""Test case for get_pet_by_id
|
||||||
|
|
||||||
|
Find pet by ID
|
||||||
|
"""
|
||||||
|
headers = {
|
||||||
|
'api_key': 'special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'GET',
|
||||||
|
'/pet/{petId}'.format(petId=56),
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_pet(client: TestClient):
|
||||||
|
"""Test case for update_pet
|
||||||
|
|
||||||
|
Update an existing pet
|
||||||
|
"""
|
||||||
|
pet = {"photo_urls":["photoUrls","photoUrls"],"name":"doggie","id":0,"category":{"name":"name","id":6},"tags":[{"name":"name","id":1},{"name":"name","id":1}],"status":"available"}
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'PUT',
|
||||||
|
'/pet',
|
||||||
|
headers=headers,
|
||||||
|
json=pet,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_pet_with_form(client: TestClient):
|
||||||
|
"""Test case for update_pet_with_form
|
||||||
|
|
||||||
|
Updates a pet in the store with form data
|
||||||
|
"""
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer special-key',
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
'name': 'name_example',
|
||||||
|
'status': 'status_example'
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'POST',
|
||||||
|
'/pet/{petId}'.format(petId=56),
|
||||||
|
headers=headers,
|
||||||
|
data=data,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_upload_file(client: TestClient):
|
||||||
|
"""Test case for upload_file
|
||||||
|
|
||||||
|
uploads an image
|
||||||
|
"""
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer special-key',
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
'additional_metadata': 'additional_metadata_example',
|
||||||
|
'file': '/path/to/file'
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'POST',
|
||||||
|
'/pet/{petId}/uploadImage'.format(petId=56),
|
||||||
|
headers=headers,
|
||||||
|
data=data,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from openapi_server.models.order import Order
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete_order(client: TestClient):
|
||||||
|
"""Test case for delete_order
|
||||||
|
|
||||||
|
Delete purchase order by ID
|
||||||
|
"""
|
||||||
|
headers = {
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'DELETE',
|
||||||
|
'/store/order/{orderId}'.format(orderId='order_id_example'),
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_inventory(client: TestClient):
|
||||||
|
"""Test case for get_inventory
|
||||||
|
|
||||||
|
Returns pet inventories by status
|
||||||
|
"""
|
||||||
|
headers = {
|
||||||
|
'api_key': 'special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'GET',
|
||||||
|
'/store/inventory',
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_order_by_id(client: TestClient):
|
||||||
|
"""Test case for get_order_by_id
|
||||||
|
|
||||||
|
Find purchase order by ID
|
||||||
|
"""
|
||||||
|
headers = {
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'GET',
|
||||||
|
'/store/order/{orderId}'.format(orderId=56),
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_place_order(client: TestClient):
|
||||||
|
"""Test case for place_order
|
||||||
|
|
||||||
|
Place an order for a pet
|
||||||
|
"""
|
||||||
|
order = {"pet_id":6,"quantity":1,"id":0,"ship_date":"2000-01-23T04:56:07.000+00:00","complete":0,"status":"placed"}
|
||||||
|
headers = {
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'POST',
|
||||||
|
'/store/order',
|
||||||
|
headers=headers,
|
||||||
|
json=order,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
154
samples/server/petstore/python-fastapi/tests/test_user_api.py
Normal file
154
samples/server/petstore/python-fastapi/tests/test_user_api.py
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from openapi_server.models.user import User
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_user(client: TestClient):
|
||||||
|
"""Test case for create_user
|
||||||
|
|
||||||
|
Create user
|
||||||
|
"""
|
||||||
|
user = {"first_name":"firstName","last_name":"lastName","password":"password","user_status":6,"phone":"phone","id":0,"email":"email","username":"username"}
|
||||||
|
headers = {
|
||||||
|
'api_key': 'special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'POST',
|
||||||
|
'/user',
|
||||||
|
headers=headers,
|
||||||
|
json=user,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_users_with_array_input(client: TestClient):
|
||||||
|
"""Test case for create_users_with_array_input
|
||||||
|
|
||||||
|
Creates list of users with given input array
|
||||||
|
"""
|
||||||
|
user = [{"first_name":"firstName","last_name":"lastName","password":"password","user_status":6,"phone":"phone","id":0,"email":"email","username":"username"}]
|
||||||
|
headers = {
|
||||||
|
'api_key': 'special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'POST',
|
||||||
|
'/user/createWithArray',
|
||||||
|
headers=headers,
|
||||||
|
json=user,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_users_with_list_input(client: TestClient):
|
||||||
|
"""Test case for create_users_with_list_input
|
||||||
|
|
||||||
|
Creates list of users with given input array
|
||||||
|
"""
|
||||||
|
user = [{"first_name":"firstName","last_name":"lastName","password":"password","user_status":6,"phone":"phone","id":0,"email":"email","username":"username"}]
|
||||||
|
headers = {
|
||||||
|
'api_key': 'special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'POST',
|
||||||
|
'/user/createWithList',
|
||||||
|
headers=headers,
|
||||||
|
json=user,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete_user(client: TestClient):
|
||||||
|
"""Test case for delete_user
|
||||||
|
|
||||||
|
Delete user
|
||||||
|
"""
|
||||||
|
headers = {
|
||||||
|
'api_key': 'special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'DELETE',
|
||||||
|
'/user/{username}'.format(username='username_example'),
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_user_by_name(client: TestClient):
|
||||||
|
"""Test case for get_user_by_name
|
||||||
|
|
||||||
|
Get user by user name
|
||||||
|
"""
|
||||||
|
headers = {
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'GET',
|
||||||
|
'/user/{username}'.format(username='username_example'),
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_login_user(client: TestClient):
|
||||||
|
"""Test case for login_user
|
||||||
|
|
||||||
|
Logs user into the system
|
||||||
|
"""
|
||||||
|
params = [("username", 'username_example'),
|
||||||
|
("password", 'password_example')]
|
||||||
|
headers = {
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'GET',
|
||||||
|
'/user/login',
|
||||||
|
headers=headers,
|
||||||
|
params=params,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_logout_user(client: TestClient):
|
||||||
|
"""Test case for logout_user
|
||||||
|
|
||||||
|
Logs out current logged in user session
|
||||||
|
"""
|
||||||
|
headers = {
|
||||||
|
'api_key': 'special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'GET',
|
||||||
|
'/user/logout',
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_user(client: TestClient):
|
||||||
|
"""Test case for update_user
|
||||||
|
|
||||||
|
Updated user
|
||||||
|
"""
|
||||||
|
user = {"first_name":"firstName","last_name":"lastName","password":"password","user_status":6,"phone":"phone","id":0,"email":"email","username":"username"}
|
||||||
|
headers = {
|
||||||
|
'api_key': 'special-key',
|
||||||
|
}
|
||||||
|
response = client.request(
|
||||||
|
'PUT',
|
||||||
|
'/user/{username}'.format(username='username_example'),
|
||||||
|
headers=headers,
|
||||||
|
json=user,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
Reference in New Issue
Block a user