Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add aiohttp server generator
  • Loading branch information
Julien Sagnard committed Jan 7, 2019
commit 2671b5bb024142125234e8322fb8aad06d2046e2
32 changes: 32 additions & 0 deletions bin/python-aiohttp-petstore.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/sh

SCRIPT="$0"
echo "# START SCRIPT: $SCRIPT"

while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done

if [ ! -d "${APP_DIR}" ]; then
APP_DIR=`dirname "$SCRIPT"`/..
APP_DIR=`cd "${APP_DIR}"; pwd`
fi

executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"

if [ ! -f "$executable" ]
then
mvn -B clean package
fi

# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -t modules/openapi-generator/src/main/resources/python-aiohttp -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g python-aiohttp -o samples/server/petstore/python-aiohttp -Dservice $@"

java $JAVA_OPTS -jar $executable $ags
1 change: 0 additions & 1 deletion bin/python-flask-petstore-python2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,4 @@ export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/
#ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g python-flask -o samples/server/petstore/flaskConnexion-python2 -DsupportPython2=true $@"
ags="generate -t modules/openapi-generator/src/main/resources/flaskConnexion -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g python-flask -o samples/server/petstore/flaskConnexion-python2 -c bin/supportPython2.json -D service $@"

rm -rf samples/server/petstore/flaskConnexion-python2/*
java $JAVA_OPTS -jar $executable $ags
1 change: 0 additions & 1 deletion bin/python-flask-petstore.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,4 @@ fi
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -t modules/openapi-generator/src/main/resources/flaskConnexion -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g python-flask -o samples/server/petstore/flaskConnexion -Dservice $@"

rm -rf samples/server/petstore/flaskConnexion/*
java $JAVA_OPTS -jar $executable $ags
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
public class CodegenSecurity {
public String name;
public String type;
public String scheme;
public Boolean hasMore, isBasic, isOAuth, isApiKey;
// is Basic is true for all http authentication type. Those are to differentiate basic and bearer authentication
public Boolean isBasicBasic, isBasicBearer;
public Map<String, Object> vendorExtensions = new HashMap<String, Object>();
// ApiKey specific
public String keyParamName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3228,6 +3228,8 @@ public List<CodegenSecurity> fromSecurity(Map<String, SecurityScheme> securitySc
cs.name = key;
cs.type = securityScheme.getType().toString();
cs.isCode = cs.isPassword = cs.isApplication = cs.isImplicit = false;
cs.isBasicBasic = cs.isBasicBearer = false;
cs.scheme = securityScheme.getScheme();

if (SecurityScheme.Type.APIKEY.equals(securityScheme.getType())) {
cs.isBasic = cs.isOAuth = false;
Expand All @@ -3239,6 +3241,12 @@ public List<CodegenSecurity> fromSecurity(Map<String, SecurityScheme> securitySc
} else if (SecurityScheme.Type.HTTP.equals(securityScheme.getType())) {
cs.isKeyInHeader = cs.isKeyInQuery = cs.isKeyInCookie = cs.isApiKey = cs.isOAuth = false;
cs.isBasic = true;
if ("basic".equals(securityScheme.getScheme())) {
cs.isBasicBasic = true;
}
else if ("bearer".equals(securityScheme.getScheme())) {
cs.isBasicBearer = true;
}
} else if (SecurityScheme.Type.OAUTH2.equals(securityScheme.getType())) {
cs.isKeyInHeader = cs.isKeyInQuery = cs.isKeyInCookie = cs.isApiKey = cs.isBasic = false;
cs.isOAuth = true;
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.languages;

import org.openapitools.codegen.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;

public class PythonAiohttpConnexionServerCodegen extends PythonAbstractConnexionServerCodegen {
private static final Logger LOGGER = LoggerFactory.getLogger(PythonAiohttpConnexionServerCodegen.class);

public PythonAiohttpConnexionServerCodegen() {
super("python-aiohttp", true);
testPackage = "tests";
embeddedTemplateDir = templateDir = "python-aiohttp";
}

/**
* Configures a friendly name for the generator. This will be used by the generator
* to select the library with the -g flag.
*
* @return the friendly name for the generator
*/
@Override
public String getName() {
return "python-aiohttp";
}

@Override
protected void addSupportingFiles() {
supportingFiles.add(new SupportingFile("conftest.mustache", testPackage, "conftest.py"));
supportingFiles.add(new SupportingFile("__init__test.mustache", testPackage, "__init__.py"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

package org.openapitools.codegen.languages;

import org.openapitools.codegen.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;

import static org.openapitools.codegen.utils.StringUtils.camelize;
Expand All @@ -27,7 +29,7 @@ public class PythonFlaskConnexionServerCodegen extends PythonAbstractConnexionSe
private static final Logger LOGGER = LoggerFactory.getLogger(PythonFlaskConnexionServerCodegen.class);

public PythonFlaskConnexionServerCodegen() {
super("flaskConnexion");
super("flaskConnexion", false);
}

/**
Expand All @@ -40,4 +42,19 @@ public PythonFlaskConnexionServerCodegen() {
public String getName() {
return "python-flask";
}

@Override
protected void addSupportingFiles() {
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
supportingFiles.add(new SupportingFile("Dockerfile.mustache", "", "Dockerfile"));
supportingFiles.add(new SupportingFile("dockerignore.mustache", "", ".dockerignore"));
supportingFiles.add(new SupportingFile("setup.mustache", "", "setup.py"));
supportingFiles.add(new SupportingFile("tox.mustache", "", "tox.ini"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("travis.mustache", "", ".travis.yml"));
supportingFiles.add(new SupportingFile("encoder.mustache", packageName, "encoder.py"));
supportingFiles.add(new SupportingFile("__init__test.mustache", packageName + File.separatorChar + testPackage, "__init__.py"));
supportingFiles.add(new SupportingFile("__init__.mustache", packageName, "__init__.py"));
testPackage = packageName + "." + testPackage;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ org.openapitools.codegen.languages.PhpZendExpressivePathHandlerServerCodegen
org.openapitools.codegen.languages.PowerShellClientCodegen
org.openapitools.codegen.languages.PythonClientCodegen
org.openapitools.codegen.languages.PythonFlaskConnexionServerCodegen
org.openapitools.codegen.languages.PythonAiohttpConnexionServerCodegen
org.openapitools.codegen.languages.RClientCodegen
org.openapitools.codegen.languages.RubyClientCodegen
org.openapitools.codegen.languages.RubyOnRailsServerCodegen
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# coding: utf-8

from __future__ import absolute_import
import unittest

from flask import json
from six import BytesIO
Expand All @@ -13,7 +14,10 @@ from {{packageName}}.test import BaseTestCase
class {{#operations}}Test{{classname}}(BaseTestCase):
"""{{classname}} integration test stubs"""

{{#operation}}
{{#operation}}
{{#vendorExtensions.x-skip-test}}
@unittest.skip("{{reason}}")
{{/vendorExtensions.x-skip-test}}
def test_{{operationId}}(self):
"""Test case for {{{operationId}}}

Expand All @@ -25,18 +29,21 @@ class {{#operations}}Test{{classname}}(BaseTestCase):
{{#queryParams}}
{{#-first}}query_string = [{{/-first}}{{^-first}} {{/-first}}('{{paramName}}', {{{example}}}){{#hasMore}},{{/hasMore}}{{#-last}}]{{/-last}}
{{/queryParams}}
{{#headerParams}}
{{#-first}}headers = [{{/-first}}{{^-first}} {{/-first}}('{{paramName}}', {{{example}}}){{#hasMore}},{{/hasMore}}{{#-last}}]{{/-last}}
{{/headerParams}}
headers = { {{#vendorExtensions.x-prefered-produce}}
'Accept': '{{mediaType}}',{{/vendorExtensions.x-prefered-produce}}{{#vendorExtensions.x-prefered-consume}}
'Content-Type': '{{mediaType}}',{{/vendorExtensions.x-prefered-consume}}{{#headerParams}}
'{{paramName}}': {{{example}}},{{/headerParams}}{{#authMethods}}
{{#isOAuth}}'Authorization': 'Bearer special-key',{{/isOAuth}}{{#isApiKey}}'{{name}}': 'special-key',{{/isApiKey}}{{#isBasic}}'Authorization': '{{#isBasicBasic}}{{#isBasicBasic}} BasicZm9vOmJhcg=={{#isBasicBearer}}Bearer special-key{{#isBasicBearer}}',{{/isBasic}}{{/authMethods}}
}
{{#formParams}}
{{#-first}}data = dict({{/-first}}{{^-first}} {{/-first}}{{paramName}}={{{example}}}{{#hasMore}},{{/hasMore}}{{#-last}}){{/-last}}
{{/formParams}}
response = self.client.open(
'{{#contextPath}}{{{.}}}{{/contextPath}}{{{path}}}'{{#pathParams}}{{#-first}}.format({{/-first}}{{paramName}}={{{example}}}{{#hasMore}}, {{/hasMore}}{{^hasMore}}){{/hasMore}}{{/pathParams}},
method='{{httpMethod}}'{{#bodyParam}},
method='{{httpMethod}}',
headers=headers{{#bodyParam}},
data=json.dumps({{paramName}}){{^consumes}},
content_type='application/json'{{/consumes}}{{/bodyParam}}{{#headerParams}}{{#-first}},
headers=headers{{/-first}}{{/headerParams}}{{#formParams}}{{#-first}},
content_type='application/json'{{/consumes}}{{/bodyParam}}{{#formParams}}{{#-first}},
data=data{{/-first}}{{/formParams}}{{#consumes}}{{#-first}},
content_type='{{{mediaType}}}'{{/-first}}{{/consumes}}{{#queryParams}}{{#-first}},
query_string=query_string{{/-first}}{{/queryParams}})
Expand All @@ -47,5 +54,4 @@ class {{#operations}}Test{{classname}}(BaseTestCase):
{{/operations}}

if __name__ == '__main__':
import unittest
unittest.main()
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ from datetime import date, datetime # noqa: F401
from typing import List, Dict # noqa: F401

from {{modelPackage}}.base_model_ import Model
{{#models}}
{{#model}}
{{#pyImports}}
{{import}}
{{/pyImports}}
{{/model}}
{{/models}}
from {{packageName}} import util

{{#imports}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
connexion == 2.0.0
connexion == 2.0.2
swagger-ui-bundle == 0.0.2
python_dateutil == 2.6.0
{{#supportPython2}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{{#authMethods}}
{{#isOAuth}}

def info_from_token_{{name}}(token):
"""
Validate and decode token.
Returned value will be available in request['token_info'].
'sub' or 'uid' will be set in request['user'].
'scope' or 'scopes' will be passed to scope validation function.
Should return None if token is invalid
"""
return {'scopes': ['read:pets', 'write:pets'], 'uid': 'user_id'}


def validate_scope_{{name}}(required_scopes, token_scopes):
""" Validate required scopes are included in token scope """
return set(required_scopes).issubset(set(token_scopes))

{{/isOAuth}}
{{#isApiKey}}

def info_from_api_key_{{name}}(api_key, required_scopes):
"""
Returned value will be available in request['token_info'].
'sub' or 'uid' will be set in request['user'].
Should return None if api_key is invalid
"""
return {'scopes': ['read:pets', 'write:pets'], 'uid': 'user_id'}

{{/isApiKey}}
{{#isBasic}}

def info_from_basic_auth_{{name}}(username, password, required_scopes):
"""
Returned value will be available in request['token_info'].
'sub' or 'uid' will be set in request['user'].
Should return None if auth is invalid
"""
return {'scopes': ['read:pets', 'write:pets'], 'uid': username}

{{/isBasic}}
{{/authMethods}}

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = {{#supportPython2}}py27, {{/supportPython2}}py35
envlist = {{#supportPython2}}py27, {{/supportPython2}}py3

[testenv]
deps=-r{toxinidir}/requirements.txt
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# OpenAPI generated server

## Overview
This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the
[OpenAPI-Spec](https://openapis.org) from a remote server, you can easily generate a server stub. This
is an example of building a OpenAPI-enabled aiohtpp server.

This example uses the [Connexion](https://github.com/zalando/connexion) library on top of aiohtpp.

## Requirements
Python 3.5.2+

## Usage
To run the server, please execute the following from the root directory:

```
pip3 install -r requirements.txt
python3 -m {{packageName}}
```

and open your browser to here:

```
http://localhost:{{serverPort}}{{contextPath}}/ui/
```

Your OpenAPI definition lives here:

```
http://localhost:{{serverPort}}{{contextPath}}/openapi.json
```

To launch the integration tests, use pytest:
```
sudo pip install -r test-requirements.txt
pytest
```

## Prevent file overriding

After first generation, add edited files to _.openapi-generator-ignore_ to prevent generator to overwrite them. Typically:
```
server/controllers/*
test/*
*.txt
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import os
import connexion


def main():
options = {
"swagger_ui": True
}
specification_dir = os.path.join(os.path.dirname(__file__), 'openapi')
app = connexion.AioHttpApp(__name__, specification_dir=specification_dir, options=options)
app.add_api('openapi.yaml', arguments={'title': '{{appName}}'}, pass_context_arg_name='request')
app.run(port={{serverPort}})
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# coding: utf-8

# import models into model package
{{#models}}{{#model}}from {{modelPackage}}.{{classFilename}} import {{classname}}{{/model}}
{{/models}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env python3

from . import main

if __name__ == '__main__':
main()
Loading