HTTP server side API¶
The Mopidy-HTTP extension comes with an HTTP server to host Mopidy’s HTTP JSON-RPC API. This web server can also be used by other extensions that need to expose something over HTTP.
The HTTP server side API can be used to:
- host static files for e.g. a Mopidy client written in pure JavaScript,
- host a Tornado application, or
- host a WSGI application, including e.g. Flask applications.
To host static files using the web server, an extension needs to register a
name and a file path in the extension registry under the http:static key.
To extend the web server with a web application, an extension must register a
name and a factory function in the extension registry under the http:app
key.
For details on how to make a Mopidy extension, see the Extension development guide.
Static web client example¶
To serve static files, you just need to register an http:static dictionary
in the extension registry. The dictionary must have two keys: name and
path. The name is used to build the URL the static files will be
served on. By convention, it should be identical with the extension’s
ext_name, like in the following example. The
path tells Mopidy where on the disk the static files are located.
Assuming that the code below is located in the file
mywebclient/__init__.py, the files in the directory
mywebclient/static/ will be made available at /mywebclient/ on
Mopidy’s web server. For example, mywebclient/static/foo.html will be
available at http://localhost:6680/mywebclient/foo.html.
from __future__ import absolute_import, unicode_literals
import os
from mopidy import ext
class MyWebClientExtension(ext.Extension):
ext_name = 'mywebclient'
def setup(self, registry):
registry.add('http:static', {
'name': self.ext_name,
'path': os.path.join(os.path.dirname(__file__), 'static'),
})
# See the Extension API for the full details on this class
Tornado application example¶
The Mopidy-HTTP extension’s web server is based on the Tornado web framework. Thus, it has first class support for Tornado request handlers.
In the following example, we create a tornado.web.RequestHandler
called MyRequestHandler that responds to HTTP GET requests with the
string Hello, world! This is Mopidy $version, where it gets the Mopidy
version from Mopidy’s core API.
To hook the request handler into Mopidy’s web server, we must register a
dictionary under the http:app key in the extension registry. The
dictionary must have two keys: name and factory.
The name is used to build the URL the app will be served on. By convention,
it should be identical with the extension’s
ext_name, like in the following example.
The factory must be a function that accepts two arguments, config and
core, respectively a dict structure of Mopidy’s config and a
pykka.ActorProxy to the full Mopidy core API. The factory function
must return a list of Tornado request handlers. The URL patterns of the request
handlers should not include the name, as that will be prepended to the URL
patterns by the web server.
When the extension is installed, Mopidy will respond to requests to
http://localhost:6680/mywebclient/ with the string Hello, world! This is
Mopidy $version.
from __future__ import absolute_import, unicode_literals
import os
import tornado.web
from mopidy import ext
class MyRequestHandler(tornado.web.RequestHandler):
def initialize(self, core):
self.core = core
def get(self):
self.write(
'Hello, world! This is Mopidy %s' %
self.core.get_version().get())
def my_app_factory(config, core):
return [
('/', MyRequestHandler, {'core': core})
]
class MyWebClientExtension(ext.Extension):
ext_name = 'mywebclient'
def setup(self, registry):
registry.add('http:app', {
'name': self.ext_name,
'factory': my_app_factory,
})
# See the Extension API for the full details on this class
WSGI application example¶
WSGI applications are second-class citizens on Mopidy’s HTTP server. The WSGI applications are run inside Tornado, which is based on non-blocking I/O and a single event loop. In other words, your WSGI applications will only have a single thread to run on, and if your application is doing blocking I/O, it will block all other requests from being handled by the web server as well.
The example below shows how a WSGI application that returns the string
Hello, world! This is Mopidy $version on all requests. The WSGI application
is wrapped as a Tornado application and mounted at
http://localhost:6680/mywebclient/.
from __future__ import absolute_import, unicode_literals
import os
import tornado.web
import tornado.wsgi
from mopidy import ext
def my_app_factory(config, core):
def wsgi_app(environ, start_response):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return [
'Hello, world! This is Mopidy %s\n' %
self.core.get_version().get()
]
return [
('(.*)', tornado.web.FallbackHandler, {
'fallback': tornado.wsgi.WSGIContainer(wsgi_app),
}),
]
class MyWebClientExtension(ext.Extension):
ext_name = 'mywebclient'
def setup(self, registry):
registry.add('http:app', {
'name': self.ext_name,
'factory': my_app_factory,
})
# See the Extension API for the full details on this class
API implementors¶
See Web extensions.