Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
16 changes: 16 additions & 0 deletions examples/openapi3/enforcedefaults_aiohttp/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
========================
Custom Validator Example
========================

In this example we fill-in non-provided properties with their defaults.
Validator code is based on example from `python-jsonschema docs`_.

Running:

.. code-block:: bash

$ ./enforcedefaults.py

Now open your browser and go to http://localhost:8080/v1/ui/ to see the Swagger
UI. If you send a ``POST`` request with empty body ``{}``, you should receive
echo with defaults filled-in.
39 changes: 39 additions & 0 deletions examples/openapi3/enforcedefaults_aiohttp/enforcedefaults-api.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
openapi: '3.0.0'
info:
version: '1'
title: Custom Validator Example
servers:
- url: http://localhost:8080/{basePath}
variables:
basePath:
default: api
paths:
/echo:
post:
description: Echo passed data
operationId: enforcedefaults.echo
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Data'
responses:
'200':
description: Data with defaults filled in by validator
default:
description: Unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Data:
type: object
properties:
foo:
type: string
default: foo
Error:
type: string
56 changes: 56 additions & 0 deletions examples/openapi3/enforcedefaults_aiohttp/enforcedefaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env python3

import firetail
import jsonschema
import six
from firetail.decorators.validation import RequestBodyValidator
from firetail.json_schema import Draft4RequestValidator


async def echo(body):
return body


# via https://python-jsonschema.readthedocs.io/
def extend_with_set_default(validator_class):
validate_properties = validator_class.VALIDATORS['properties']

def set_defaults(validator, properties, instance, schema):
for property, subschema in six.iteritems(properties):
if 'default' in subschema:
instance.setdefault(property, subschema['default'])

for error in validate_properties(
validator, properties, instance, schema):
yield error

return jsonschema.validators.extend(
validator_class, {'properties': set_defaults})

DefaultsEnforcingDraft4Validator = extend_with_set_default(Draft4RequestValidator)


class DefaultsEnforcingRequestBodyValidator(RequestBodyValidator):
def __init__(self, *args, **kwargs):
super(DefaultsEnforcingRequestBodyValidator, self).__init__(
*args, validator=DefaultsEnforcingDraft4Validator, **kwargs)


validator_map = {
'body': DefaultsEnforcingRequestBodyValidator
}


if __name__ == '__main__':
app = firetail.AioHttpApp(
__name__,
port=8080,
specification_dir='.',
options={'swagger_ui': True}
)
app.add_api(
'enforcedefaults-api.yaml',
arguments={'title': 'Hello World Example'},
validator_map=validator_map,
)
app.run()
11 changes: 11 additions & 0 deletions examples/openapi3/helloworld_aiohttp/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
===================
Hello World Example
===================

Running:

.. code-block:: bash

$ ./hello.py

Now open your browser and go to http://localhost:9090/v1.0/ui/ to see the Swagger UI.
14 changes: 14 additions & 0 deletions examples/openapi3/helloworld_aiohttp/hello.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env python3

import firetail
from aiohttp import web


async def post_greeting(name):
return web.Response(text=f'Hello {name}')


if __name__ == '__main__':
app = firetail.AioHttpApp(__name__, port=9090, specification_dir='openapi/')
app.add_api('helloworld-api.yaml', arguments={'title': 'Hello World Example'})
app.run()
30 changes: 30 additions & 0 deletions examples/openapi3/helloworld_aiohttp/openapi/helloworld-api.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
openapi: "3.0.0"

info:
title: Hello World
version: "1.0"
servers:
- url: http://localhost:9090/v1.0

paths:
/greeting/{name}:
post:
summary: Generate greeting
description: Generates a greeting message.
operationId: hello.post_greeting
responses:
200:
description: greeting response
content:
text/plain:
schema:
type: string
example: "hello dave!"
parameters:
- name: name
in: path
description: Name of the person to greet.
required: true
schema:
type: string
example: "dave"
58 changes: 58 additions & 0 deletions examples/openapi3/reverseproxy_aiohttp/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
=====================
Reverse Proxy Example
=====================

This example demonstrates how to run a firetail application behind a path-altering reverse proxy.

You can either set the path in your app, or set the ``X-Forwarded-Path`` header.

Running:

.. code-block:: bash

$ sudo pip3 install --upgrade firetail[swagger-ui] aiohttp-remotes
$ ./app.py

Now open your browser and go to http://localhost:8080/reverse_proxied/ui/ to see the Swagger UI.


You can also use the ``X-Forwarded-Path`` header to modify the reverse proxy path.
For example:

.. code-block:: bash

curl -H "X-Forwarded-Path: /banana/" http://localhost:8080/openapi.json

{
"servers" : [
{
"url" : "banana"
}
],
"paths" : {
"/hello" : {
"get" : {
"responses" : {
"200" : {
"description" : "hello",
"content" : {
"text/plain" : {
"schema" : {
"type" : "string"
}
}
}
}
},
"operationId" : "app.hello",
"summary" : "say hi"
}
}
},
"openapi" : "3.0.0",
"info" : {
"version" : "1.0",
"title" : "Path-Altering Reverse Proxy Example"
}
}

82 changes: 82 additions & 0 deletions examples/openapi3/reverseproxy_aiohttp/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env python3
'''
example of aiohttp firetail running behind a path-altering reverse-proxy
'''

import json
import logging

import firetail
from aiohttp import web
from aiohttp_remotes.exceptions import RemoteError, TooManyHeaders
from aiohttp_remotes.x_forwarded import XForwardedBase
from yarl import URL

X_FORWARDED_PATH = "X-Forwarded-Path"


class XPathForwarded(XForwardedBase):

def __init__(self, num=1):
self._num = num

def get_forwarded_path(self, headers):
forwarded_host = headers.getall(X_FORWARDED_PATH, [])
if len(forwarded_host) > 1:
raise TooManyHeaders(X_FORWARDED_PATH)
return forwarded_host[0] if forwarded_host else None

@web.middleware
async def middleware(self, request, handler):
logging.warning(
"this demo is not secure by default!! "
"You'll want to make sure these headers are coming from your proxy, "
"and not directly from users on the web!"
)
try:
overrides = {}
headers = request.headers

forwarded_for = self.get_forwarded_for(headers)
if forwarded_for:
overrides['remote'] = str(forwarded_for[-self._num])

proto = self.get_forwarded_proto(headers)
if proto:
overrides['scheme'] = proto[-self._num]

host = self.get_forwarded_host(headers)
if host is not None:
overrides['host'] = host

prefix = self.get_forwarded_path(headers)
if prefix is not None:
prefix = '/' + prefix.strip('/') + '/'
request_path = URL(request.path.lstrip('/'))
overrides['rel_url'] = URL(prefix).join(request_path)

request = request.clone(**overrides)

return await handler(request)
except RemoteError as exc:
exc.log(request)
await self.raise_error(request)


def hello(request):
ret = {
"host": request.host,
"scheme": request.scheme,
"path": request.path,
"_href": str(request.url)
}
return web.Response(text=json.dumps(ret), status=200)


if __name__ == '__main__':
app = firetail.AioHttpApp(__name__)
app.add_api('openapi.yaml', pass_context_arg_name='request')
aio = app.app
reverse_proxied = XPathForwarded()
aio.middlewares.append(reverse_proxied.middleware)
app.run(port=8080)
38 changes: 38 additions & 0 deletions examples/openapi3/reverseproxy_aiohttp/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
worker_processes 1;
error_log stderr;
daemon off;
pid nginx.pid;

events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

sendfile on;

keepalive_timeout 65;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
access_log access.log;
server {

listen localhost:9000;

location /reverse_proxied/ {
# Define the location of the proxy server to send the request to
proxy_pass http://localhost:8080/;
# Add prefix header
proxy_set_header X-Forwarded-Path /reverse_proxied/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto http;
}

}
}
18 changes: 18 additions & 0 deletions examples/openapi3/reverseproxy_aiohttp/openapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
openapi: 3.0.0
info:
title: Path-Altering Reverse Proxy Example
version: '1.0'
servers:
- url: /api
paths:
/hello:
get:
summary: say hi
operationId: app.hello
responses:
'200':
description: hello
content:
text/plain:
schema:
type: string
14 changes: 14 additions & 0 deletions examples/swagger2/basicauth/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
=======================
HTTP Basic Auth Example
=======================

Running:

.. code-block:: bash

$ sudo pip3 install --upgrade firetail[swagger-ui] # install Firetail from PyPI
$ ./app.py

Now open your browser and go to http://localhost:8080/ui/ to see the Swagger UI.

The hardcoded credentials are ``admin:secret`` and ``foo:bar``.
Loading