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:
Nikita Vakula
2021-05-30 11:43:31 +02:00
committed by GitHub
parent dee2840b20
commit 0da4099868
52 changed files with 3483 additions and 0 deletions

View 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"

View 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

View File

@@ -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);
}
}

View File

@@ -97,6 +97,7 @@ org.openapitools.codegen.languages.PowerShellClientCodegen
org.openapitools.codegen.languages.ProtobufSchemaCodegen
org.openapitools.codegen.languages.PythonLegacyClientCodegen
org.openapitools.codegen.languages.PythonClientCodegen
org.openapitools.codegen.languages.PythonFastAPIServerCodegen
org.openapitools.codegen.languages.PythonFlaskConnexionServerCodegen
org.openapitools.codegen.languages.PythonAiohttpConnexionServerCodegen
org.openapitools.codegen.languages.PythonBluePlanetServerCodegen

View 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

View 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
```

View 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}}

View 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}}

View 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)

View 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}}

View File

@@ -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}}")

View File

@@ -0,0 +1,8 @@
# coding: utf-8
from pydantic import BaseModel
class TokenModel(BaseModel):
"""Defines a token model."""
sub: str

View 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/

View 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}}

View 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}}

View File

@@ -0,0 +1 @@
{{{openapi-yaml}}}

View 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}}

View 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
"""

View 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

View 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

View 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}}

View 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

View 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/

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1 @@
5.2.0-SNAPSHOT

View 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

View 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
```

View File

@@ -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

View 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

View 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

View 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

View 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 &#x60;special-key&#x60; 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

View File

@@ -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
...

View File

@@ -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 &lt; 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 &lt;&#x3D; 5 or &gt; 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
...

View File

@@ -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."""
...

View File

@@ -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 &#x60;special-key&#x60; to test the authorization filters.",
version="1.0.0",
)
app.include_router(PetApiRouter)
app.include_router(StoreApiRouter)
app.include_router(UserApiRouter)

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,8 @@
# coding: utf-8
from pydantic import BaseModel
class TokenModel(BaseModel):
"""Defines a token model."""
sub: str

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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)

View 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

View File

@@ -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

View 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