-
-
Notifications
You must be signed in to change notification settings - Fork 762
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Run an API spec, no boilerplate needed #284
Merged
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
c74d8cd
Provide CLI support for runnning specifications
rafaelcaricio e9d5a61
Run with specification stubs
rafaelcaricio 9c5f6bc
Refine stub option
rafaelcaricio 82dcb61
Pass along all options available
rafaelcaricio e7f96e4
Sort imports
rafaelcaricio 97adb25
Sort imports
rafaelcaricio 8ef5794
Merge master into cli branch
rafaelcaricio d9b59c6
Fix imports
rafaelcaricio 7ecb585
Fix imports
rafaelcaricio 186f33b
Use clickclick>=1.2 with support to Python 2.7
rafaelcaricio dbe20e9
Remove cnx alias to CLI
rafaelcaricio 07c6eb7
Fix parameters in the CLI interface
rafaelcaricio 2208a95
Directories to be considered modules in Python2.7 needs to contain a …
rafaelcaricio b024a90
Add basic logging to CLI for troubleshooting
rafaelcaricio fec010b
Document connexion run command
rafaelcaricio 6076f96
Fix typo
rafaelcaricio 9b7cb99
Check that all options are passed correctly from the CLI module
rafaelcaricio a2c074d
Make connexion executable
rafaelcaricio b3fc3ff
Very simple code to run module, no tests :(
rafaelcaricio b57ebfa
No coverage for those two lines
rafaelcaricio 46fa019
Use INFO log level by default
rafaelcaricio c1d55c1
Support different log levels in CLI
rafaelcaricio d71674b
Make sure very verbose is the same as debug
rafaelcaricio 08b20e5
Fix flake8 checks
rafaelcaricio 2d23ac9
Nicer verbosity impl.
rafaelcaricio File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from connexion.cli import main # pragma: no cover | ||
|
||
main() # pragma: no cover |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import logging | ||
import sys | ||
from os import path | ||
|
||
import click | ||
from clickclick import AliasedGroup, fatal_error | ||
from connexion import App | ||
|
||
logger = logging.getLogger('connexion.cli') | ||
|
||
main = AliasedGroup(context_settings=dict(help_option_names=[ | ||
'-h', '--help'])) | ||
|
||
|
||
def validate_wsgi_server_requirements(ctx, param, value): | ||
if value == 'gevent': | ||
try: | ||
import gevent # NOQA | ||
except: | ||
fatal_error('gevent library is not installed') | ||
elif value == 'tornado': | ||
try: | ||
import tornado # NOQA | ||
except: | ||
fatal_error('tornado library is not installed') | ||
|
||
|
||
@main.command() | ||
@click.argument('spec_file') | ||
@click.argument('base_module_path', required=False) | ||
@click.option('--port', '-p', default=5000, type=int, help='Port to listen.') | ||
@click.option('--wsgi-server', '-w', default='flask', | ||
type=click.Choice(['flask', 'gevent', 'tornado']), | ||
callback=validate_wsgi_server_requirements, | ||
help='Which WSGI server container to use.') | ||
@click.option('--stub', | ||
help='Returns status code 501, and `Not Implemented Yet` payload, for ' | ||
'the endpoints which handlers are not found.', | ||
is_flag=True, default=False) | ||
@click.option('--hide-spec', | ||
help='Hides the API spec in JSON format which is by default available at `/swagger.json`.', | ||
is_flag=True, default=False) | ||
@click.option('--hide-console-ui', | ||
help='Hides the the API console UI which is by default available at `/ui`.', | ||
is_flag=True, default=False) | ||
@click.option('--console-ui-url', metavar='URL', | ||
help='Personalize what URL path the API console UI will be mounted.') | ||
@click.option('--console-ui-from', metavar='PATH', | ||
help='Path to a customized API console UI dashboard.') | ||
@click.option('--auth-all-paths', | ||
help='Enable authentication to paths not defined in the spec.', | ||
is_flag=True, default=False) | ||
@click.option('--validate-responses', | ||
help='Enable validation of response values from operation handlers.', | ||
is_flag=True, default=False) | ||
@click.option('--strict-validation', | ||
help='Enable strict validation of request payloads.', | ||
is_flag=True, default=False) | ||
@click.option('--debug', '-d', help='Show debugging information.', | ||
is_flag=True, default=False) | ||
@click.option('--verbose', '-v', help='Show verbose information.', count=True) | ||
def run(spec_file, | ||
base_module_path, | ||
port, | ||
wsgi_server, | ||
stub, | ||
hide_spec, | ||
hide_console_ui, | ||
console_ui_url, | ||
console_ui_from, | ||
auth_all_paths, | ||
validate_responses, | ||
strict_validation, | ||
debug, | ||
verbose): | ||
""" | ||
Runs a server compliant with a OpenAPI/Swagger 2.0 Specification file. | ||
|
||
Arguments: | ||
|
||
- SPEC_FILE: specification file that describes the server endpoints. | ||
|
||
- BASE_MODULE_PATH (optional): filesystem path where the API endpoints handlers are going to be imported from. | ||
""" | ||
logging_level = logging.WARN | ||
if verbose > 0: | ||
logging_level = logging.INFO | ||
|
||
if debug or verbose > 1: | ||
logging_level = logging.DEBUG | ||
debug = True | ||
|
||
logging.basicConfig(level=logging_level) | ||
|
||
spec_file_full_path = path.abspath(spec_file) | ||
py_module_path = base_module_path or path.dirname(spec_file_full_path) | ||
sys.path.insert(1, path.abspath(py_module_path)) | ||
logger.debug('Added {} to system path.'.format(py_module_path)) | ||
|
||
resolver_error = None | ||
if stub: | ||
resolver_error = 501 | ||
|
||
app = App(__name__, | ||
swagger_json=not hide_spec, | ||
swagger_ui=not hide_console_ui, | ||
swagger_path=console_ui_from or None, | ||
swagger_url=console_ui_url or None, | ||
auth_all_paths=auth_all_paths, | ||
debug=debug) | ||
|
||
app.add_api(spec_file_full_path, | ||
resolver_error=resolver_error, | ||
validate_responses=validate_responses, | ||
strict_validation=strict_validation) | ||
|
||
app.run(port=port, | ||
server=wsgi_server, | ||
debug=debug) | ||
|
||
|
||
if __name__ == '__main__': # pragma: no cover | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
Command-Line Interface | ||
====================== | ||
For convenience Connexion provides a command-line interface | ||
(CLI). This interface aims to be a starting point in developing or | ||
testing OpenAPI specifications with Connexion. | ||
|
||
The available commands are: | ||
|
||
- ``connexion run`` | ||
|
||
All commands can run with -h or --help to list more information. | ||
|
||
Running an OpenAPI specification | ||
-------------------------------- | ||
|
||
The subcommand ``run`` of Connexion's CLI makes it easy to run OpenAPI | ||
specifications directly even before any operation handler function gets | ||
implemented. This allows you to verify and inspect how your API will | ||
work with Connexion. | ||
|
||
To run your specification, execute in your shell: | ||
|
||
.. code-block:: bash | ||
|
||
$ connexion run your_api.yaml --stub --debug | ||
|
||
This command will tell Connexion to run the ``your_api.yaml`` | ||
specification file attaching a stub operation (``--stub``) to the | ||
unavailable operations/functions of your API and in debug mode | ||
(``--debug``). | ||
|
||
The basic usage of this command is: | ||
|
||
.. code-block:: bash | ||
|
||
$ connexion run [OPTIONS] SPEC_FILE [BASE_MODULE_PATH] | ||
|
||
Where: | ||
|
||
- SPEC_FILE: Your OpenAPI specification file in YAML format. | ||
- BASE_MODULE_PATH (optional): filesystem path where the API endpoints | ||
handlers are going to be imported from. In short, where your Python | ||
code is saved. | ||
|
||
There are more options available for the ``run`` command, for a full | ||
list run: | ||
|
||
.. code-block:: bash | ||
|
||
$ connexion run --help |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ Contents: | |
:maxdepth: 2 | ||
|
||
quickstart | ||
cli | ||
routing | ||
request | ||
response | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
|
||
import connexion | ||
from connexion import NoContent | ||
|
||
import orm | ||
|
||
db_session = None | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,4 @@ requests>=2.9.1 | |
six>=1.7 | ||
strict-rfc3339>=0.6 | ||
swagger_spec_validator>=2.0.2 | ||
clickclick>=1.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
swagger: "2.0" | ||
|
||
info: | ||
title: "Testing API" | ||
version: "1.0" | ||
|
||
basePath: "/testing" | ||
|
||
paths: | ||
/operation-not-implemented: | ||
get: | ||
summary: Operation function does not exist. | ||
operationId: api.this_function_does_not_exist | ||
responses: | ||
200: | ||
description: OK |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
swagger: "2.0" | ||
|
||
info: | ||
title: "Not Exist API" | ||
version: "1.0" | ||
|
||
basePath: '/na' | ||
|
||
paths: | ||
/module-not-implemented: | ||
get: | ||
summary: Operation function does not exist. | ||
operationId: m.module_does_not_exist | ||
responses: | ||
200: | ||
description: OK |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a future improvement we could implement a resolver that mocks a response based on the specification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is definitely interesting. There are some open source tools that do that, but bringing together the possibility to have partially mocked API's, that can morph in a fully implemented one, is a new approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I'm looking to do is use my resolving swagger parser prance to generate test cases for an API. That's coming from realizing that swagger-tester isn't quite what I'd like it to be.
Some of that code might well be useful for generating the mocked response. One way or another it's going through the spec and generating stuff.
Just a thought. But I can't guarantee I'll be able to spend time on that.