hugapi / hug Goto Github PK
View Code? Open in Web Editor NEWEmbrace the APIs of the future. Hug aims to make developing APIs as simple as possible, but no simpler.
License: MIT License
Embrace the APIs of the future. Hug aims to make developing APIs as simple as possible, but no simpler.
License: MIT License
Hug should automatically convert NamedTuple's into associative arrays for the JSON output format
The initial example in the doco says
localhost:8080/happy_birthday?name=Hug&age=1
but the default is 8000 causing initial confusion.
Not a biggie but might confuse newcomers.
Kudos on your work! I'll be watching to see where it goes.
The half-baked idea I'd like to work on sometime (when I get time):
Up till now, hypermedia APIs have not gotten as much as attention as they deserve, arguably because they are designed for a theoretical client that doesn't actually exist. What if this client did exist in the form of code completion and validation engines for multiple languages? By existing only as a helper for the developer, it might avoid the mess of CORBA and SOAP.
Hug could make this easy if it used the HTTP Link Header to return type information. For example, it could return the following for the /users
API endpoint:
{
"@context": "http://schema.org/",
"@type": "Person",
"@typedef": "http://www.janedoe.com/typedefs/person.d.ts"
}
With http://www.janedoe.com/typedefs/person.d.ts being something like this (using Typescript to describe JSON because JSON Schema is unwieldy):
interface Person
{
name: string;
jobTitle?: string;
telephone?: string;
url?: string;
}
And a sample response body for a GET request:
{
"name": "Jane Doe",
"jobTitle": "Professor",
"telephone": "(425) 123-4567",
"url": "http://www.janedoe.com"
}
Related:
My Ubuntu is 14.04 and I just install the latest Python version and setup_tools.
I install hug with sudo pip3 install hug --upgrade
successfully. But When I try to import hug in REPL, I got such error:
Python 3.2.3 (default, Jun 18 2015, 21:46:42)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import hug
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.2/dist-packages/hug/__init__.py", line 32, in <module>
from hug import (authentication, directives, documentation, exceptions, format,
File "/usr/local/lib/python3.2/dist-packages/hug/authentication.py", line 25, in <module>
from falcon import HTTPUnauthorized
File "/usr/local/lib/python3.2/dist-packages/falcon/__init__.py", line 32, in <module>
from falcon.api import API, DEFAULT_MEDIA_TYPE # NOQA
File "/usr/local/lib/python3.2/dist-packages/falcon/api.py", line 22, in <module>
from falcon.request import Request, RequestOptions
File "/usr/local/lib/python3.2/dist-packages/falcon/request.py", line 38
DEFAULT_ERROR_LOG_FORMAT = (u'{0:%Y-%m-%d %H:%M:%S} [FALCON] [ERROR]'
^
SyntaxError: invalid syntax
It also happened when I directly import in a Python file.
Due to use of markdown, and some conversion issues, readme is not formatted correctly once it makes its way to PYPI
First off, like this API simple and strait to the point.
I've used hug to build a simple REST API layer to another api, I would like to log the request body and parameters to be used at a later date for application data analytics (pretty graphs!) but there doesn't seem to be a clear way to this indicated by documentation, something as simple as this:
import hug
@hug.get('/version')
def get_version();
info(response.body);
Would suffice, is the response functions only available in the application middleware?
I'm having some problem in a toy app, I'm experiencing a server error in Firefox but not in Chrome (same client).
Diving in the code I noticed the problem is related with the dictionary lookup in HugAPI.input_format.
return getattr(self, '_input_format', {}).get(content_type, hug.defaults.input_format.get(content_type, None))
Whenever the content type is composed nothing matches.
An easy workaround is to strip after the ;
but generally a real fix requires an encoding argument floating around, with an UTF-8
default.
I'd like to help, you'd like to discuss an approach to solve the problem?
Hey, great work!
Do you have plans for future features? I would like to help the project. Maybe you could create issues tagged as bugs or enhancements.
I've just come across hug as I'm writing a new API and it looks simple, but very effective :)
I'm currently adding authentication using request_middleware as this:
import hug
from falcon import HTTP_FORBIDDEN
@hug.request_middleware()
def process_data(request, response):
if 'X-API-Key' not in request.headers:
response.body='403 Forbidden'
response.status=HTTP_FORBIDDEN
@hug.get('/test', versions=1)
def test(text):
print(text)
return {'text': text}
This works fine, and returns a 403, however it continues to process the endpoint (I see the text on the console).
Is there a (sane) way to stop this from happening?
The default output formatters should be updated to handle error dictionary outputs, either by correctly formatting the data into their format, or by returning a JSON result.
see: #156
There should be an overview of the architecture and thoughts behind it somewhere within the hug repo. This will also help new contributors get a since of how to contribute and what files serve what purposes within the code base.
It would be useful to list instructions on getting hug setup for development / contributing from a Windows based machine. Since I do not own any computers running Windows personally, this is an area where I could really use another contributor's help to ensure the instructions are correct.
Is there a way to import modules/libraries that are not decorated with @hug? I must be missing something obvious?
Here what I'm getting:
C:\Users\mike\PycharmProjects\hugs\person> hug -f .\app.py
Traceback (most recent call last):
File "C:\Users\mike\AppData\Local\Programs\Python\Python35\lib\runpy.py", line 170, in _run_module_as_main
"__main__", mod_spec)
File "C:\Users\mike\AppData\Local\Programs\Python\Python35\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Users\mike\AppData\Local\Programs\Python\Python35\Scripts\hug.exe\__main__.py", line 9, in <module>
File "C:\Users\mike\AppData\Local\Programs\Python\Python35\lib\site-packages\hug\run.py", line 147, in terminal
api = server(importlib.machinery.SourceFileLoader(file_name.split(".")[0], file_name).load_module())
File "<frozen importlib._bootstrap_external>", line 383, in _check_name_wrapper
File "<frozen importlib._bootstrap_external>", line 804, in load_module
File "<frozen importlib._bootstrap_external>", line 663, in load_module
File "<frozen importlib._bootstrap>", line 268, in _load_module_shim
File "<frozen importlib._bootstrap>", line 693, in _load
File "<frozen importlib._bootstrap>", line 673, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 660, in exec_module
File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
File ".\app.py", line 2, in <module>
import person
ImportError: No module named 'person'
Thanks!
Hi,
Any idea on how to enable CORS or set Header on per end point basis ? If I use middleware it will be for all request, won't it ?
Thanks in advance
Hug should enable easily extending the serialization capabilities of the framework with support for serializing API specific data types
The coding standards document indicates that the code in this project should conform to PEP 8, which specifies PEP 257 docstrings. My pull request #176 changed the files that it touched. I would be happy to take care of converting the rest of the project if you like.
It would be useful to allow easily switching the output format on case of a validation error.
To enable this we should add an output_invalid
argument to the HTTPRouter object that will be used on validation errors if specified, and will default to the overall output_format if not.
It would be really cool if you could use hug APIs locally via Python, in a way that made changing to remote usage during production use as simple as a single line / config change.
If a decorator has 'versions' set all endpoints without 'versions' set do not show up in the documentation. Is this an intended feature?
There should be a document at the root of the repository that explains the process and concerns that should be taken when contributing to hug, to encourage more contributors.
Hug is great! May I suggest adding:
I don't know why the presence of an output formatter would affect making sure required parameters are present...
'''
Both of these have a single parameter named "data".
If you call the one without the output formatter, it correctly notices the missing parameter.
If you call the one with the output formatter, it raises a server error.
'''
import hug
@hug.get('/without_output_formatter')
def with_output_formatter(data):
'''
If called without the required parameter, gives you ...
HTTP/1.0 400 Bad Request
Date: Mon, 01 Feb 2016 04:09:15 GMT
Server: WSGIServer/0.2 CPython/3.4.3+
content-length: 55
content-type: application/json
{
"errors": {
"data": "Required parameter not supplied"
}
}
'''
return 'Without Output Formatter'
@hug.get('/with_output_formatter',output=hug.output_format.svg_xml_image)
def without_output_formatter(data):
'''
If called without the required parameter, gives you ...
HTTP/1.0 500 Internal Server Error
Content-Length: 59
Content-Type: text/plain
Date: Mon, 01 Feb 2016 04:09:09 GMT
Server: WSGIServer/0.2 CPython/3.4.3+
A server error occurred. Please contact the administrator.
'''
return 'With Output Formatter'
It would be useful if hug could optionally auto generate RAML style documentation, in addition to it's default json documentation format. For more information on the spec see: http://raml.org/
https://www.python.org/dev/peps/pep-0484/ provides an optional way to write functions that enable type linters etc to extract information in a standard way from annotations. Hug should be expanded to support users who choose to follow this pep.
transform
parameter on the decorator that can be used instead of the ->
syntax->
annotation points to the same type, nothing happens at all on outputtransform
is set to False
, nothing should happen even if an annotation is specified that does not have the same typeAdd ability to add defined commands such as test
and build
that get routed via the hug runner.
For example:
hug -f my_api.py build --db my_db
Enabled by
@hug.cmd():
def build(db):
# do db build here
Thanks @BrandonHoffman for the idea!
It would be useful to enable routing to be done separate from the handler functions to better support alternative directory structures and workflows:
api.py
import hug
import library
api = hug.API(__name__)
api.get('/api_call_1')(library.function_1)
api.class_based('/api_calls_2')(library.class_1)
That would also allow easy routing of existing internal Python only APIs without code changes
It's important to note, however, that this would need to be done in addition to the default behavior of decorating functions, and would not be replacing it.
Split off from here: #31. Ideally, hug would automatically restart a dev API when the files used to create it changed. This would streamline the user workflow when using hug.
I whipped up a quick example from looking through the decorators.py source:
__init__.py
import hug
from . import something
@hug.get('/')
def say_hi():
return "Hi from root"
@hug.extend_api('/something')
def something_api():
return [something]
#alternatively
__hug__.extend(something, '/something')
something.py
import hug
@hug.get('/')
def say_hi():
return 'hello from something'
Currently, you can specify how data that comes in is processed using annotation type handlers. It would be cool if you could specify how outputted data should be structured (in Python) using the return or ->
annotation. Just like input types this should be separate from it's content_type / output_format
It would beneficial to have a secondary custom validator that could be set for API endpoints. This would allow easy support for things such as verifying one field or another was present within the scope of the validation process.
Right now hug only supports versioning on a straight numeric value, this works fairly well in most cases where no breaking changes happen between major releases, however it can occasionally fall apart - which unfortunately could lead to the hug API version not staying at all in sync with the codes semantic version. It would be beneficial to support semantic versioning routes natively in hug. One potential way to do this would be to allow a length 3 tuple to be passed into the tuple in addition to a straight int. A convenience named tuple object could be added to make usage explicit:
@hug.get(versions=hug.version(major=3, minor=2))
def endpoint():
pass
thanks @vortec for the idea!
The function that creates documentation should be moved from it's own module to live inside of the hug API singleton. This would allow easily retrieving documentation from other modules for introspection reasons, as well as easy customization of the documentation produced.
If the example for splitting APIs across multiple files is followed an error occurs when no directives are defined, due to incorrect default in the code:
(testhug) william@Williams-MBP:~/projects/testhug/multi$ hug -f __init__.py
Traceback (most recent call last):
File "/Users/william/projects/testhug/bin/hug", line 11, in <module>
sys.exit(run.terminal())
File "/Users/william/projects/testhug/lib/python3.4/site-packages/hug/run.py", line 171, in terminal
api = server(importlib.machinery.SourceFileLoader(file_name.split(".")[0], file_name).load_module(),
File "<frozen importlib._bootstrap>", line 539, in _check_name_wrapper
File "<frozen importlib._bootstrap>", line 1614, in load_module
File "<frozen importlib._bootstrap>", line 596, in _load_module_shim
File "<frozen importlib._bootstrap>", line 1220, in load
File "<frozen importlib._bootstrap>", line 1200, in _load_unlocked
File "<frozen importlib._bootstrap>", line 1129, in _exec
File "<frozen importlib._bootstrap>", line 1471, in exec_module
File "<frozen importlib._bootstrap>", line 321, in _call_with_frames_removed
File "__init__.py", line 10, in <module>
@hug.extend_api('/thing')
File "/Users/william/projects/testhug/lib/python3.4/site-packages/hug/decorators.py", line 194, in decorator
module.__hug__.extend(api, route)
File "/Users/william/projects/testhug/lib/python3.4/site-packages/hug/decorators.py", line 97, in extend
for directive in getattr(module.__hug__, '_directives', ()).values():
AttributeError: 'tuple' object has no attribute ‘values’
This needs to be fixed ASAP and prior to the next release. A test should be added to guarantee this wont happen again.
When I use this method:
@hug.get()
def newline():
s = """this is a string
with a newline
"""
return s
I get the following output from http://localhost:8000/newline
:
"this is a string\nwith a newline\n"
Is it possible to prevent the newline being replaced?
There should be a hug.length
type that allows validating against the length of a passed in field and transforming it to a specific Python type (defaulting to string). This would allow quickly building endpoints that accept for instance names under a curtain string length:
@hug.post()
def user(name: hug.length(0, 10)):
pass # logic goes here
I am writing an API that needs to change output based on which user is logged in. I really like what I've been able to do with hug so far, but I'm not really seeing a clean way to do this at this point. Ideally, the functions would be able to access some kind of session information.
I know auth is implemented as nicely wrapped falcon middleware at the moment, so this may be rather tricky to pull off plumbing wise. If you arrive at a high-levl solution and are open to contributions, I'd be happy to contribute, as I do have a pressing use case for this.
Hug should ideally have built-in support for the circuit breakers pattern as it is a very core component of any modern resilient micro-service.
https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern
It uses a mock module that doesn't seem to exist in Python 2. When using Python3 it works fine.
Is this project supposed to be Python3 only?
Traceback (most recent call last):
File "main.py", line 1, in <module>
import hug
File "/usr/local/lib/python2.7/dist-packages/hug/__init__.py", line 32, in <module>
from hug import (authentication, directives, documentation, exceptions, format,
File "/usr/local/lib/python2.7/dist-packages/hug/test.py", line 26, in <module>
from unittest import mock
ImportError: cannot import name mock
Tried with version 1.9.3 installed using pip.
The Hug_timer directive appears to be recording the start time but not correctly keeping track of time as it passes
hug internally creates a 'hug' singleton object on every module where hug routes or utilities are defined. It would be neat if you could do this explicitly as well as implicitly. For example:
api = hug.API(__name__)
api == __hug__
this could enable cleaner usage in some circumstances.
It would be cool to be able to pass in a list of transformers instead of just a single transformer. A quick and consistent way to implement would be a transform.multiple
transformation function that took a list of transforming functions.
In order to encourage more modules to be built that extend hug capabilities it would be useful to build a guiding document that describes the process to extend and use hug extensions.
The testing facilities included in hug are really nice. However, when writing tests against your own APIs declared in separate files, there appear to be two small issues.
First, the README seems to indicate that you can test by passing in the module with your API to hug.test.get
or a similar function. However, it appears that you actually need to pass your_module.__hug__
as the first argument to hug.test.get
. I'm not sure if this is just outdated documentation or a legitimate bug.
Second, assuming the above is the correct way to test a module, py.test seems to hang after finishing the tests. This appears to only be an issue when importing APIs from another module. Declaring API endpoints inline seems to work, but this is obviously not feasible when writing tests against your nicely structure set of API files ;) I'm guessing that there is some "server" thread that is not exiting after the tests?
I want to be able to run/debug my services in eclipse/pydev. I faked it by doing this in my hug API file:
if __name__ == '__main__':
import sys
from hug import run
# run.terminal() gets its args from sys.argv so give it what it expects
sys.argv[0] = "hug"
sys.argv.extend(['-f', __file__])
run.terminal()
and it seems to work.
Is there a better way that I have missed?
I am trying to decorate the methods of a class as API calls but I can't make it ignore the 'self' parameter. Is it possibly to manually set the accepted parameters, or set it to ignore one?
It should be possible to cleanly route any request to the 404 handling page a user has setup independent of where in the processing the 404 occurred, and without requiring a redirect.
Currently the one_of
type handler returns a somewhat cryptic error message, it should be updated to clearly state the problem that occurred.
hug should (optionally) allow the user to configure a route to raise on validation errors, instead of collecting the errors into an error dict. This would be the quickest to process option, allow short-circuit validation, and allow the errors to pass to their overall exception handlers.
Traceback:
Traceback (most recent call last): File "/home/rye/.virtualenvs/hug/bin/hug", line 11, in <module> sys.exit(run.terminal()) File "/home/rye/.virtualenvs/hug/lib/python3.5/site-packages/hug/run.py", line 171, in terminal **server_arguments) TypeError: server() got an unexpected keyword argument 'sink'
Tested on a very basic Hug-app with only a single get-handler.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.