From ee355607cfbbff98c3894dba4bc941d3ad655073 Mon Sep 17 00:00:00 2001 From: Brandon Rodriguez <brodriguez8774@gmail.com> Date: Fri, 1 Mar 2024 15:54:33 -0500 Subject: [PATCH] Update Djangov4 API to include a "send" testing view --- django_v4/test_app/forms.py | 35 ++++ .../test_app/templates/test_app/api_send.html | 176 ++++++++++++++++++ .../test_app/templates/test_app/index.html | 5 +- django_v4/test_app/urls.py | 1 + django_v4/test_app/views.py | 119 +++++++++++- 5 files changed, 325 insertions(+), 11 deletions(-) create mode 100644 django_v4/test_app/forms.py create mode 100644 django_v4/test_app/templates/test_app/api_send.html diff --git a/django_v4/test_app/forms.py b/django_v4/test_app/forms.py new file mode 100644 index 0000000..85e2b4e --- /dev/null +++ b/django_v4/test_app/forms.py @@ -0,0 +1,35 @@ +""" +Forms for Django v4.2 test project app. +""" + +# System Imports. + +# Third-Party Imports. +from django import forms + +# Internal Imports. + + +class ApiSendForm(forms.Form): + """A single line item for sending in an API call.""" + + url = forms.URLField() + get_params = forms.CharField( + required=False, + widget=forms.Textarea(attrs={'rows': '6'}), + help_text='Optional URL get param to append to URL.', + ) + header_token = forms.CharField( + required=False, + widget=forms.Textarea(attrs={'rows': '6'}), + help_text='Optional token to put into request header, such as required for API authentication.' + ) + payload = forms.CharField( + required=False, + widget=forms.Textarea(attrs={'rows': '20'}), + help_text=( + 'Should be in proper JSON dictionary format or else will error. <br><br>' + 'Ex: Use double quotes instead of single, booleans should be lower case, etc. <br><br>' + 'If left empty, will send <br>{"success": true}.' + ) + ) diff --git a/django_v4/test_app/templates/test_app/api_send.html b/django_v4/test_app/templates/test_app/api_send.html new file mode 100644 index 0000000..22421f4 --- /dev/null +++ b/django_v4/test_app/templates/test_app/api_send.html @@ -0,0 +1,176 @@ +{% extends "test_app/base.html" %} + +{% block page_header %} + Django LTS v4.2 - API Send +{% endblock page_header %} + + +{% block page_subheader %} + API Send Page +{% endblock page_subheader %} + + +{% block stylesheets %} +<style> + form { + padding: 10px; + border: 1px solid grey; + } + + form div { + padding-top: 5px; + padding-bottom: 5px; + } + + input { + width: 100%; + } + + textarea { + width: 100%; + } + + pre { + width: 100%; + margin: 5px; + padding: 5px; + background-color: LightSteelBlue; + } + + .error { + color: red; + } + + .field-group { + display: flex; + flex-direction: row; + width: 100%; + } + + .label p { + margin-top: 8px; + margin-bottom: 8px; + } + + .label { + width: 10%; + padding: 0 10px 0 10px; + text-align: right; + } + + .help-text { + font-size: 70%; + font-style: italic; + text-align: center; + } + + .field { + width: 80%; + padding: 0 10px 0 10px; + } +</style> +{% endblock stylesheets %} + +{% block content %} + <p>Use this to generate and send test API requests to other projects.</p> + + <form method="POST"> + {% csrf_token %} + + {% if form.non_field_errors %} + <div class="error"> + <p>Non Field Errors:</p> + {{ form.non_field_errors }} + </div> + <hr> + {% endif %} + + {% for field in form %} + + <div> + {% if field.errors %} + <p class="error"> Field Error: + {% for error in field.errors %} + {{ error }} + {% endfor %} + </p> + {% endif %} + + <div class="field-group"> + + <div class="label"> + <p>{{ field.label }}:</p> + {% if field.help_text %} + <p class="help-text">{{ field.help_text|safe }}</p> + {% endif %} + </div> + <div class="field"> + {{ field }} + </div> + </div> + + </div> + + {% endfor %} + + <input type="submit" value="Submit"> + </form> + + <div class="example"> + <h2>Example Send Values:</h2> + + <div class="field-group"> + <div class="label"> + <p> + Url: + </p> + </div> + <pre>http://127.0.0.1:8000/test_app/api/parse/</pre> + </div> + <div class="field-group"> + <div class="label"> + <p> + Get Params: + </p> + </div> + <pre>test-param-1=Abc&test-param-2=123</pre> + </div> + <div class="field-group"> + <div class="label"> + <p> + Header Token: + </p> + </div> + <pre>MyExampleHeaderAuthToken-112233445566778899ABABCDCD</pre> + </div> + <div class="field-group"> + <div class="label"> + <p> + Payload: + </p> + </div> + <pre>{ + "test": true, + "Aaa": "Bbb", + "MyNumber": 5 +}</pre> + </div> + </div> + + <hr> + + <p>Above values will send:</p> + <pre>url: http://127.0.0.1:8000/test_app/api/parse/?test-param-1=Abc&test-param-2=123 + +header: { + "Accept": "application/json", + "token": "MyExampleHeaderAuthToken-112233445566778899ABABCDCD" +} + +data: { + "test": true, + "Aaa": "Bbb", + "MyNumber": 5 +}</pre> + +{% endblock content %} diff --git a/django_v4/test_app/templates/test_app/index.html b/django_v4/test_app/templates/test_app/index.html index 199ed9a..782eb48 100644 --- a/django_v4/test_app/templates/test_app/index.html +++ b/django_v4/test_app/templates/test_app/index.html @@ -29,7 +29,7 @@ <p>API Views:</p> <ul> <li> - <p><a href="{% url 'test_app:api_parse' %}">API Parse - Send API requests here to parse them.</a></p> + <p><a href="{% url 'test_app:api_parse' %}">API Parse - Receive API requests here to parse them.</a></p> </li> <li> <p><a href="{% url 'test_app:api_display' %}">API Display - View parsed API requests here.</a></p> @@ -39,6 +39,9 @@ All parsed API data is purged after page access. </p> </li> + <li> + <p><a href="{% url 'test_app:api_send' %}">API Send - Generate and send API requests here.</a></p> + </li> </ul> </li> </ul> diff --git a/django_v4/test_app/urls.py b/django_v4/test_app/urls.py index b7db94c..e9245a2 100644 --- a/django_v4/test_app/urls.py +++ b/django_v4/test_app/urls.py @@ -19,6 +19,7 @@ urlpatterns = [ # Test API views. path('api/parse/', views.api_parse, name='api_parse'), path('api/display/', views.api_display, name='api_display'), + path('api/send/', views.api_send, name='api_send'), # App root. path('', views.index, name='index') diff --git a/django_v4/test_app/views.py b/django_v4/test_app/views.py index 7d5f08b..5437a2a 100644 --- a/django_v4/test_app/views.py +++ b/django_v4/test_app/views.py @@ -1,19 +1,21 @@ """ -Views for Django v4.1 test project app. +Views for Django v4.2 test project app. """ # System Imports. import json import html +import requests # Third-Party Imports. from django.contrib.auth.decorators import login_required, permission_required -from django.http import JsonResponse, QueryDict +from django.http import HttpResponse, JsonResponse, QueryDict from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods from django.shortcuts import redirect, render, reverse # Internal Imports. +from test_app.forms import ApiSendForm from test_app.models import ApiRequestJson @@ -70,17 +72,49 @@ def api_parse(request): Allows quick debugging to make sure the expected, correct data is being sent. """ + print('') + print('api_parse():') + # Get data from response. - data = {'data': 'No data found in request.'} + get_data = {} + post_data = {} + body_data = {} + header_data = {} + if request.headers: + print('Received HEADERS:') + header_data = dict(request.headers) + print(header_data) if request.GET: - data = request.GET - elif request.POST: - data = dict(request.POST) - elif request.body: + print('Received GET:') + get_data = _recurisive_json_parse(request.GET) + for key, value in get_data.items(): + get_data[key] = value[0] + print(get_data) + if request.POST: + print('Received POST:') + post_data = _recurisive_json_parse(dict(request.POST)) + print(post_data) + if request.body: + print('Received BODY:') # Attempt to escape. Limited functionality so may not work. - data = html.unescape(request.body.decode('UTF-8')) - - data = _recurisive_json_parse(data) + # To be precise, functions well with a standard JSON response. + # But with any other response type that has a body, might break and be ugly. + body_data = _recurisive_json_parse(html.unescape(request.body.decode('UTF-8'))) + print(body_data) + print('\n') + + # Combine data. + data = {} + if header_data: + data['HEADERS'] = header_data + if get_data: + data['GET'] = get_data + if post_data: + data['POST'] = post_data + if body_data: + data['body'] = body_data + if not data: + data = {'data': 'No data found in request.'} # Save api data to database. model_instance = ApiRequestJson.objects.first() @@ -154,4 +188,69 @@ def api_display(request): # Return data view to user. return response + +def api_send(request): + """Test app index page.""" + print('\n') + print('api_send():') + + # Get initial data. + form_initial = [{ + 'is_str': True, + 'value': 'This is a test entry.' + }] + + # Initialize formset. + form = ApiSendForm() + + # Check if POST. + if request.POST: + # Is POST. Process data. + print('Is POST submission.') + + data = request.POST + form = ApiSendForm(data=data) + + if form.is_valid(): + # Handle for form submission. + print('Submitted form data:') + print('{0}'.format(form.cleaned_data)) + + url = str(form.cleaned_data['url']).strip() + get_params = str(form.cleaned_data.get('get_params', '')).strip() + header_token = str(form.cleaned_data.get('header_token', '')).strip() + payload = json.loads(str(form.cleaned_data.get('payload', {})).strip()) + + # Determine url. + if get_params and len(get_params) > 0: + if url[-1] != '?' and get_params[0] != '?': + url += '?' + url += get_params + + # Determine header values. + headers = {'Accept': 'application/json'} + if header_token: + headers['token'] = header_token + + # Determine data values. + if payload: + data = json.dumps(payload) + else: + data = json.dumps({'success': True}) + + # Generate API send object. + response = requests.post( + url, + headers=headers, + data=data, + timeout=5, + ) + + print('Rendering response...') + print('') + + return render(request, 'test_app/api_send.html', { + 'form': form, + }) + # endregion API Views -- GitLab