Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Submission to Implement Frontend for usaddress API call #43

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,11 @@ module.exports = {
"space-in-parens": ["error", "never"],
"space-before-function-paren": ["error", "always"],
"space-before-blocks": ["error", "always"]
},
"parserOptions": {
"ecmaVersion": "latest"
},
"env": {
"es6": true
}
}
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
#
# Read more on Dockerfile best practices at the source:
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices
RUN apt-get update && apt-get install -y --no-install-recommends postgresql-client nodejs
RUN apt-get update && apt-get install -y --no-install-recommends postgresql-client nodejs npm

# Inside the container, create an app directory and switch into it
RUN mkdir /app
Expand Down
2 changes: 0 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: '2.4'

services:
app:
image: parserator
Expand Down
58 changes: 56 additions & 2 deletions parserator_web/static/js/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,56 @@
/* TODO: Flesh this out to connect the form to the API and render results
in the #address-results div. */
'use strict'

// TODO: We'll want to change this url in production, obviously
const url = "http://localhost:8000/api/parse"
const submitButton = document.getElementById("submit")

// We'll save the blank results html for use later
let blankTable = document.getElementById("address-table").innerHTML

submitButton.onclick = async function (event) {
event.preventDefault()

let results = document.getElementById("address-results")

// We'll blank this out in case we get an error
// So that we don't show old responses as if to new queries
results.style.display = "none"

let addressString = document.getElementById("address").value
let queryTerms = new URLSearchParams({ address: addressString })
try {
const response = await fetch(`${url}?${queryTerms}`)
console.log(response)
if (!response.ok) {
if (response.status == 400) {
alert(`${response.statusText}: Failed to parse this address`)
} else {
// TODO: Handle other failures?
}
} else {
let responseData = await response.json()

// Set the headline
document.getElementById("parse-type").textContent = responseData.address_type

// Build the table
let table = document.getElementById("address-table")
table.innerHTML = blankTable
let addressParts = responseData.address_components
for (let index in addressParts) {
let field = addressParts[index][0]
let value = addressParts[index][1]

let nextRow = table.insertRow(-1)
let fieldData = nextRow.insertCell(0)
let valueData = nextRow.insertCell(1)

fieldData.appendChild(document.createTextNode(field))
valueData.appendChild(document.createTextNode(value))
}
results.style.display = "block"
}
} catch (error) {
console.error(`${error} in response to query at ${url}?{queryTerms}`)
}
}
2 changes: 1 addition & 1 deletion parserator_web/templates/parserator_web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ <h3 id="usaddress-parser"><i class="fa fa-fw fa-map-marker-alt"></i> U.S. addres
<div id="address-results" style="display:none">
<h4>Parsing results</h4>
<p>Address type: <strong><span id="parse-type"></span></strong></p>
<table class="table table-bordered">
<table class="table table-bordered" id="address-table">
<thead>
<tr>
<th>Address part</th>
Expand Down
23 changes: 17 additions & 6 deletions parserator_web/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,22 @@ class AddressParse(APIView):
renderer_classes = [JSONRenderer]

def get(self, request):
# TODO: Flesh out this method to parse an address string using the
# parse() method and return the parsed components to the frontend.
return Response({})
input_string = request.GET.get("address")
try:
components, address_type = self.parse(input_string)
address_components = []
for comp in components:
address_components.append((comp, components[comp]))
return Response({"input_string": input_string,
"address_components": address_components,
"address_type": address_type})
except ParseError:
return Response({"error": "This address failed to parse"}, status=400)

def parse(self, address):
# TODO: Implement this method to return the parsed components of a
# given address using usaddress: https://github.com/datamade/usaddress
return address_components, address_type
# We'll let our library to the heavy lifting here
# And we'll re-throw the usaddress exception as a ParseError
try:
return usaddress.tag(address)
except usaddress.RepeatedLabelError:
raise ParseError
2 changes: 0 additions & 2 deletions tests/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: '2.4'

services:
app:
# Don't restart the service when the command exits
Expand Down
21 changes: 14 additions & 7 deletions tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import pytest


def test_api_parse_succeeds(client):
# TODO: Finish this test. Send a request to the API and confirm that the
# data comes back in the appropriate format.
# We're going to test just the status code and json of the response
# Testing of e.g., templates or contexts should be done elsewhere
address_string = '123 main st chicago il'
pytest.fail()
response = client.get("/api/parse", {"address": address_string}, follow=True)
assert response.json() == {"address_components": [["AddressNumber", "123"],
["StreetName", "main"],
["StreetNamePostType", "st"],
["PlaceName", "chicago"],
["StateName", "il"]],
"address_type": "Street Address",
"input_string": "123 main st chicago il"}
assert response.status_code == 200


def test_api_parse_raises_error(client):
# TODO: Finish this test. The address_string below will raise a
# RepeatedLabelError, so ParseAddress.parse() will not be able to parse it.
address_string = '123 main st chicago il 123 main st'
pytest.fail()
response = client.get("/api/parse", {"address": address_string}, follow=True)
assert response.json() == {"error": "This address failed to parse"}
assert response.status_code == 400