Skip to main content

asyncio simple HTTP Server

This package contains a really Simple Http API Server using asyncio. It is not meant to be used in production. It is more a lightweight alternative to SimpleHTTPServer but for writing HTTP APIs.

Install the package

You can find the package at https://pypi.org/project/asyncio-simple-http-server.
Python >=3.8 is required. To install or upgrade you can use:

$ pip install --upgrade asyncio-simple-http-server

Usage Example

To start the server is the usual straightforward asyncio server code, plus some registration for your HTTP API handlers.

from asyncio_simple_http_server import HttpServer
import asyncio

async def main():
    # Create an instance of the HTTP Server
    http_server = HttpServer()

    # Register one or more handlers
    # The handlers are classes containing your APIs
    # See below for an example and more information.
    http_server.add_handler(MyHandler())

    # If you need to enable CORS to call the APIs
    # from a web console that you are building (e.g. angular, react, ...)
    # just add the following line,
    # to add the required header to all the responses.
    http_server.add_default_response_headers({
        'Access-Control-Allow-Origin': '*'
    })

    # start the server and serve/wait forever
    await http_server.start('127.0.0.1', 8888)
    await http_server.serve_forever()

if __name__ == '__main__':
    asyncio.run(main())

An handler is a simple class where some methods can be exposed as an HTTP API, using a simple annotation. It also tries to simplify things for REST by converting the request body from json to a dict and the response object to json using the json.loads() and json.dumps() methods.

from asyncio_simple_http_server import uri_mapping

class MyHandler:
    # The @uri_mapping decorator exposes this method as an HTTP API
    # so you can just do a HTTP GET /test-get
    # and you'll get back a 200 OK with a json body of {a: 10}
    # return values will be converted with json.dumps()
    @uri_mapping('/test-get')
    def test_get(self):
        return {'a': 10}

    # In this case the mapping says that we want a POST method
    # and by passing an argument named 'body' we will get the
    # body passed to the endpoint parsed with json.loads()
    # We execute "some logic" and we return the body
    @uri_mapping('/test-post', method='POST')
    def test_post(self, body):
      foo = body.get('foo')
      print('foo:', foo)
      return body

Special Parameter Names

To receive the data of the HTTP request we use special parameter names, so if name a variable:

  • request: will contains an HttpRequest object, which is the full request (method, path, header, body).
  • headers: will contains an HttpHeaders object, which is a map of header name to values (a key can have multiple values).
  • query_params will contains a dict[str, list[str]], which is a map of the query param name to list of values.
  • raw_body: will contains the raw body as bytes.
  • body: will contains the body converted from json using json.loads().
  • uri_variables: will contains a dict of the variable specified in the @uri_variable_mapping and extracted from the path.

Custom HTTP responses (status code, headers, ...)

You can return an HttpResponse object to customize the response with your status code, headers and body encoding. You can also send a file by specifying the file path instead of the body.

from asyncio_simple_http_server import uri_mapping, HttpResponse, HttpHeaders

class MyHandler:
    # You can return an HttpResponse object to set
    # custom status code, headers and body
    @uri_mapping('/test-custom-response')
    def test_custom_resp(self) -> HttpResponse:
        headers = HttpHeaders()
        headers.set('X-Foo', 'custom stuff')
        return HttpResponse(200, headers, b'test-body')

    # With an HttpResponse object
    # you can also send a file that is on disk
    @uri_pattern_mapping('/send-my-file')
    def test_file(self) -> HttpResponse:
        return HttpResponse(200, file_path='/path/of/my-file')

Response Exceptions

You can also control the flow using HttpResponseException. If not catched by your code it will result in a response with the http status code, headers and body specified.

@uri_mapping('/test-exception')
def test_exception(self):
    headers = HttpHeaders()
    headers.set('X-Foo', 'custom stuff')
    raise HttpResponseException(400, headers, b'custom-body')

Routes with patterns

Sometimes static routes are not enough. and you want a dynamic pattern. You can use @uri_variable_mapping and @uri_pattern_mapping to do exactly that.

from asyncio_simple_http_server import HttpRequest, uri_variable_mapping, uri_pattern_mapping

class MyHandler:
    # You can also map routes with variables
    # for example you can call this one with /aaa/FOO/ccc/BAR
    # and you'll get {'bbb': 'FOO', 'ddd', 'BAR'} as uri_variables
    @uri_variable_mapping('/aaa/{bbb}/ccc/{ddd}')
    def test_due(self, uri_variables: dict):
        return uri_variables

    # Or you can use regex patterns to match what you want
    # for example here you can call it as /any/FOO/BAR or /any/ZOO
    @uri_pattern_mapping('/any/(.*)')
    def test_pattern(self, request: HttpRequest):
        return request.path

Oh, It uses asyncio

Oh yeah, I almost forgot. This server uses asyncio, so your function can be async too. just add async to the method and use all the awaits that you want.

class MyHandler:
    @uri_mapping('/async-sleep')
    async def test_async_sleep(self):
        await asyncio.sleep(4)

Metadata

Release files for asyncio-simple-http-server 0.0.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for asyncio-simple-http-server 0.0.8
File Size Uploaded
asyncio_simple_http_server-0.0.8.tar.gz 21.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for asyncio-simple-http-server 0.0.8
File Interpreter ABI Platform
asyncio_simple_http_server-0.0.8-py3-none-any.whl Python 3 none any Details

Total release size: 41.8 kB

Release files / asyncio_simple_http_server-0.0.8.tar.gz

Download URL asyncio_simple_http_server-0.0.8.tar.gz
Size 21.9 kB
Tags Source
SHA-256 checksum
How to use checksums
2db0bf70b47ccebff1893bb978c3727d3e9490520a1d1aaf163fdcac7d3fe009
BLAKE2b-256 checksum
How to use checksums
9a3a1c39c86778d15d1caafb1d25f651076f9c0ea365539d67ba49e4502fa0d3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.12.6

Release files / asyncio_simple_http_server-0.0.8-py3-none-any.whl

Download URL asyncio_simple_http_server-0.0.8-py3-none-any.whl
Size 19.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
97f9a37639c357ab57d6832de5d735f3b52fe236e832e5189713d6b0413fdf52
BLAKE2b-256 checksum
How to use checksums
07ec2d156fee8c3c57bcae26283a5b6a43cc08d633b0169f6099df5e8016ca5a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.12.6

Release history Release notifications | RSS feed

This release

0.0.8 This release

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page