Development
Setup development environment¶
git clone https://github.com/mondeja/http-request-codegen.git
python3 -m virtualenv venv
. venv/bin/activate
python3 -m pip install .[dev]
pre-commit install
git clone https://github.com/mondeja/http-request-codegen.git
python3 -m virtualenv venv
venv\Scripts\activate.bat
python3 -m pip install .[dev]
pre-commit install
Development commands¶
Test¶
pytest -sv
pytest -s --cov=http_request_codegen --cov-config=setup.cfg --cov-report=html
pytest -svv --doctest-modules http_request_codegen
Lint¶
pre-commit run --all-files
Developing implementations¶
To develop an HTTP method function for a library or a program, you need to take in accounts all parameters described in generate_http_request_code
function, but not the randomized values passed in parameters
argument, because http_request_codegen
provides functions that can handle these.
Implementation arguments¶
Each implementation function must contain the following arguments, which are passed from the API function generate_http_request_code
, so it's recommended that you familiarize yourself with the arguments of that function before continuing with this guide because they are well documented there:
url
: unique positional argument of the function, represents the target URL of the request.headers
: dictionary of headers.parameters
: list of parameter data objects.files
: dictionary of files, only passed to POST requests, so this should not be defined as argument is the function implementation's name is different topost
.wrap
: maximum anchor of the rendered code snippet.indent
: indentation used in the rendered code snippet.quote_char
: string quotation character.setup
: code snippet prepended to generated request output.teardown
: code snippet appended at the end of the generated request output.oneline
: if enabled, render the code snippet in one line.seed
: seed used generating random fake values of parameters.locale
: locale used by faker library to localize the faked random values for parameters.
Method singularities¶
POST¶
Most POST methods implementations render their code snippets different,
depending on *Content-Types* header, including by default some of the
most used *Content-Types* header related behaviours:
- The default behavior, even if you don't specify it explicitly in the
*Content-Type* header is the generation of an
`application/x-www-form-urlencoded` encoded request.
- If you want to generate a ``multipart/form-data`` encoded request,
you need to specify the files to sent using the ``files`` argument.
- If you specifies the *Content-Type* header `application/json`, the
parameters sent will be adjusted according to the JSON encoded POST
request.
- If you specifies the *Content-Type* header `text/plain`, you can only
send one parameter and it will be adjusted accordingly following
the implementation.
One line wrapping behaviour¶
The first thing to take in account (and the most complicated one) is the behaviour of wrapping (wrap
argument) rendering as if oneline=True
is passed. The question is: can a snippet of code be outputted in one line if the estimated length of the request is lower than wrap
argument value?
For example, Python requests can be rendered using this kind of code, in one line:
import requests
req = requests.get('https://github.com/mondeja/http-request-codegen')
...or using multiple lines (wrap
is lower than expected length):
import requests
req = requests.get(
'https://github.com/mondeja/http-request-codegen'
)
Of course, this also affects parameters
, headers
and kwargs
:
import requests
req = requests.get('localhost', params={'foo': 'bar'}, headers={'foo': 'bar'})
...which can be outputted in multiple lines:
import requests
req = requests.get(
'localhost',
params={'foo': 'bar'},
headers={'foo': 'bar'}
)
Since this behaviour can depend both oneline
and wrap
arguments, the recommended way of implement this is to calculate the length of the expected request inside the code snippet, and, if it is greater or equal to wrap
argument, must be rendered as if oneline=True
.
Tip
You can see an example of this type of implementation at http_request_codegen.generators.python.requests::get
function.
But other implementations could be rendered in multiples lines regardless the wrap
argument value.
For example, the Javascript fetch API implementation will output always a multiline code snippet (unless oneline=True
is explicitly defined), because the Javascript Promises writing in single line is not a common syntax and there is a little chance that the generated request could not be wrapped given the default wrap value (80 in this case). The minimum reasonable possible code snippet in one line for Javascript fetch API implementation would be:
fetch('localhost').then(function(response) {}).catch(function(error) {console.error(error)});
...which exceeds the default wrap
value length (80). In such type of cases, there is no need of calculate the expected generated code snippet request length before build their output.
Tip
You can see an example of this type of implementation at http_request_codegen.generators.javascript.fetch::get
function.
In the first case, you need to iterate over parameters
, headers
and kwargs
arguments to compute the expected length, then compare the expected length with wrap
argument value and, if it reaches it, define an internal oneline=True
like behaviour. In the second, you can assume that the generated code is multiline unless oneline=True
is explicitly defined as argument.
Randomizing values¶
The library provides the functions lazy_name_by_parameter
and lazy_value_by_parameter
which returns the name and the value of a parameter given a parameter dictionary specification. These must be used to randomize parameters in a unified way across implementations as described in generate_http_request_code
function documentation.
Language/platform utilities¶
You can create an _utils.py
module inside a language or platform package to store utilities that could help in the process of building the code snippet, like:
- Define default indentation for the language/platform (
indent
argument). - Define default wrapping length value (
wrap
argument). - Define default quotation character/s (
quote_char
argument). - Escape quotes of values (according to given
quote_char
argument). - Create greater level functions of code generation for the language/platform, such as string definitions with wrapping behaviour, dictionary definitions...
Tip
See current _utils.py
modules of generators
packages as reference.
Creating test cases¶
Use the script scripts/create-impl-test-cases.py
to create possible generated code snippets cases accordingly to combination of arguments. This will help you developing implementations because saves you the need of execute every possible combination of arguments. Use it as follows:
rm -rf cases && python3 scripts/create-impl-test-cases.py \
--language python \
--implementation requests \
--method GET \
--directory cases
Previous command will create a cases/
directory with a lot of code snippets generated, given the combinations described in tests/combinations.py
.
When you will have manually revised that all code snippets are generated correctly, you can create a test for the implementation at tests/test_generators/test_<lang>/test_<impl>/test_<impl>.py
, placing the cases/
directory at tests/test_generators/test_<lang>/test_<impl>/<METHOD>
.
For example, for Python requests GET method, the test module would be tests/test_generators/test_python/test_requests/test_requests.py
and the cases/
directory would be placed at tests/test_generators/test_python/test_requests/GET/
.
Tip
You can use an already implemented test module as a reference to write the one for the implementation.