-
Notifications
You must be signed in to change notification settings - Fork 30
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
EXPERIMENTAL FEATURE: API Overview Page #72
base: master
Are you sure you want to change the base?
Changes from 10 commits
f30c5eb
2769302
fe2cd9a
07c2bd3
c3c929e
d4bf9d6
817e3a6
35eee6e
456b0f4
8844d34
6aacc8d
fa5dfcb
dfeab61
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,11 @@ | ||
import cgi | ||
from webob import Request, Response | ||
from webob.exc import HTTPNotFound | ||
from jinja2 import FileSystemLoader, Environment | ||
import json | ||
import logging | ||
from .validator import validate_args, ValidationError | ||
from .utils import json_encode, is_file, FileIter | ||
from .utils import json_encode, is_file, FileIter, get_template_path | ||
from .version import __version__ | ||
import threading | ||
|
||
|
@@ -22,6 +23,10 @@ | |
ctx = threading.local() | ||
ctx.request = None | ||
|
||
loader = FileSystemLoader(searchpath=get_template_path()) | ||
env = Environment(loader=loader) | ||
template = env.get_template('index.html') | ||
|
||
class Firefly(object): | ||
def __init__(self, auth_token=None): | ||
self.mapping = {} | ||
|
@@ -47,6 +52,20 @@ def generate_index(self): | |
} | ||
return help_dict | ||
|
||
def generate_showcase(self, **kwargs): | ||
functions = [ | ||
{'name': name, 'path': spec['path'], 'doc': spec['doc'], 'parameters': spec['parameters']} | ||
for name, spec in self.generate_function_list().items() | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't the following line simple enough?
You are calling the function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
html = template.render({ | ||
'host_url': kwargs['host_url'], | ||
'functions': functions | ||
}) | ||
response = Response(content_type='text/html') | ||
response.status = 200 | ||
response.text = html | ||
return response | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. |
||
def __call__(self, environ, start_response): | ||
request = Request(environ) | ||
response = self.process_request(request) | ||
|
@@ -73,7 +92,9 @@ def process_request(self, request): | |
ctx.request = request | ||
|
||
path = request.path_info | ||
if path in self.mapping: | ||
if path == "/docs": | ||
return self.generate_showcase(host_url=request.environ['HTTP_HOST']) | ||
elif path in self.mapping: | ||
func = self.mapping[path] | ||
response = func(request) | ||
else: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<title>{% if name %}{{ name }} | {% else %}{% endif %}firefly | API Browser</title> | ||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> | ||
<style type="text/css"> | ||
.bs-example{ | ||
margin: 20px; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div class="container"> | ||
<br> | ||
<h3>{% if name %}{{ name }} | {% else %}{% endif %}firefly | API Browser</h3> | ||
{% if version %} | ||
<p><b>Version: </b>{{ version }}</p> | ||
{% endif %} | ||
<div class="row"> | ||
<div class="col-md-6"> | ||
<div class="bs-firefly"> | ||
{% for function in functions %} | ||
<div class="panel-group" id="accordion"> | ||
<div class="panel panel-default"> | ||
<div class="panel-heading"> | ||
<h4 class="panel-title"> | ||
<div class="pull-right">{{ function.path }}</div> | ||
<a data-toggle="collapse" data-parent="#accordion" href="#collapse{{ loop.index }}">{{ function.name }}</a> | ||
</h4> | ||
</div> | ||
<div id="collapse{{ loop.index }}" class="panel-collapse collapse in"> | ||
<div class="panel-body"> | ||
<p> | ||
{% if function.doc %} | ||
{{ function.doc }} | ||
{% else %} | ||
<i>No docstring provided</i> | ||
{% endif %} | ||
</p> | ||
<h4>Parameters</h4> | ||
<ul> | ||
{% for param in function.parameters %} | ||
<li>{{ param.name }}</li> | ||
{% endfor %} | ||
</ul> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
{% endfor %} | ||
</div> | ||
</div> | ||
<div class="col-md-6"> | ||
<p>The API can be used by using firefly-client</p> | ||
<p>Install it using:</p> | ||
<div class="well"> | ||
<samp> | ||
$ pip install firefly | ||
</samp> | ||
</div> | ||
<p>Usage:</p> | ||
<div class="well"> | ||
<samp> | ||
>>> import firefly<br/> | ||
>>> client = firefly.Client('{{ host_url }}')<br/> | ||
>>> client.function_name(<parameters>)<br/> | ||
<function_response> | ||
</samp> | ||
</div> | ||
</div> | ||
</div> | ||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> | ||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> | ||
</body> | ||
</html> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please split this into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is that really needed? For future use cases? |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,11 @@ def json_encode(data): | |
def is_file(obj): | ||
return hasattr(obj, "read") | ||
|
||
def get_template_path(): | ||
firefly_module = __import__('firefly') | ||
file = firefly_module.__file__ | ||
return '/'.join(file.split('/')[:-1]) + '/templates' | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See my comments in |
||
class FileIter: | ||
def __init__(self, fileobj, chunk_size=4096): | ||
self.fileobj = fileobj | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ WebOb==1.7.2 | |
requests>=2.18.1 | ||
PyYAML==3.12 | ||
funcsigs==1.0.2 ; python_version < '3' | ||
Jinja2==2.10 |
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.
You can use
PackageLoader
instead computing the template path. See http://jinja.pocoo.org/docs/2.10/api/#basics.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.
Ah! I didnt know about this. This is a robust abstraction.