In [ ]:
import sys
sys.path.append('/opt/rhc')
and importing a couple of components.
In [ ]:
import rhc.micro as micro
import rhc.async as async
Connections to HTTP resources can be defined using the
CONNECTION and RESOURCE directives in a micro file.
A simple definition follows.
In [ ]:
p=micro.load_connection([
'CONNECTION placeholder http://jsonplaceholder.typicode.com',
'RESOURCE document /posts/1',
])
Now, make a connection and see what happens.
In [ ]:
async.wait(micro.connection.placeholder.document(_trace=True))
This code performs a GET on http://jsonplaceholder.typicode.com/posts/1 and prints the result.
There are simpler ways to perform this task, like using the wonderful requests library, but
this solution is designed to perform well in a microservice environment where numerous connections
are being handled simultaneously.
load_connectionThe load_connection helper function
allows for the dynamic loading of connection definitions. In this case, the definition is contained
in a list, but could also be loaded from a file by specifying the file's name, or by specifying
a dot-separated path to the file in the python code tree.
In a microservice implementation, the connection definitions are included in the
micro file, or in one of the imported files.
This function is included for experimentation and development.
The CONNECTION directive provides a name and a url for a service. The connection is
added to rhc.micro, and can be accessed as rhc.micro.connection.{name}.
Since rhc.micro is imported as micro, the rhc preface is skipped in the example.
All by itself, a CONNECTION doesn't provide much.
The RESOURCE directive adds a specific HTTP resource to the most recently specified CONNECTION.
In this case, the resource name is document and the path to the resource is /posts/1;
when combined with the CONNECTION, the full resource url is
http://jsonplaceholder.typicode.com/posts/1.
The resource is added to the connection, and can be accessed as
micro.connection.{connection name}.{resource name} or, specifically,
micro.connection.placeholder.document.
waitThe wait helper function starts a connection to the resource and waits until
it is done, printing the result.
This hints at the asynchronous activity underpinning micro.connection, which
will become more apparent in subsequent examples.
In a microservice, the wait function is never used, since it would cause the
entire service to block until wait completes.
This function is included for testing and development.
In [ ]:
micro.load_connection([
'CONNECTION placeholder http://jsonplaceholder.typicode.com',
'RESOURCE document /posts/{document_id}',
])
which adds a required argument to the micro.connection.placeholder.document function.
Now the wait call looks like this:
In [ ]:
async.wait(micro.connection.placeholder.document(1))
In [ ]:
micro.load_connection([
'CONNECTION placeholder http://jsonplaceholder.typicode.com',
'RESOURCE document /posts/{document_id} trace=true',
])
This will log the entire HTTP document when it is sent, making it easy for us to see what is going on. Make sure to enable debug logging, by doing something like the following:
In [ ]:
import logging
logging.basicConfig(level=logging.DEBUG)
Note: In a production microservice, you should never use trace=debug. Documents
often contain sensitive information that you don't want to end
up in logs.
A json document will be assembled from the keyword arguments to
micro.connection.placeholder.document. Try running the example with this
wait call:
In [ ]:
async.wait(micro.connection.placeholder.document('1', a=1, b=2))
In [ ]:
micro.load_connection([
'CONNECTION placeholder http://jsonplaceholder.typicode.com',
'RESOURCE document /posts/{document_number} trace=true',
'REQUIRED first_name',
'OPTIONAL planet default=earth',
])
The document resource now has two required arguments: document_id from
the path and first_name from the REQUIRED directive.
If the optional argument planet is not supplied, it will use the default value
of earth.
Run the example with this wait call:
In [ ]:
async.wait(micro.connection.placeholder.document(1, 2))
Note: path substitutions come first, in left-to-right order as
encountered in the path, followed, in order, by each REQUIRED argument.
OPTIONAL arguments, if specified, can be in any order.