Skip to content

Commit

Permalink
feat: search cities by a search string
Browse files Browse the repository at this point in the history
Closes #12
  • Loading branch information
matheuspiment committed Oct 8, 2019
1 parent 9062d1a commit 53cddbe
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 1 deletion.
142 changes: 142 additions & 0 deletions __tests__/integration/controllers/CityController.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/* eslint-disable @typescript-eslint/camelcase */

import request from 'supertest'
import moxios from 'moxios'

import app from '../../../src/app'

describe('CityController', () => {
beforeEach(function () {
moxios.install()
})

afterEach(function () {
moxios.uninstall()
})

describe('search', () => {
it('should return the cities when the request is mada with valid args', async () => {
moxios.wait(() => {
const request = moxios.requests.mostRecent()
request.respondWith({
status: 200,
response: {
predictions: [
{
description: 'Victoria, BC, Canadá',
id: 'd5892cffd777f0252b94ab2651fea7123d2aa34a',
matched_substrings: [
{
length: 4,
offset: 0
}
],
place_id: 'ChIJcWGw3Ytzj1QR7Ui7HnTz6Dg',
reference: 'ChIJcWGw3Ytzj1QR7Ui7HnTz6Dg',
structured_formatting: {
main_text: 'Victoria',
main_text_matched_substrings: [
{
length: 4,
offset: 0
}
],
secondary_text: 'BC, Canadá'
},
terms: [
{
offset: 0,
value: 'Victoria'
},
{
offset: 10,
value: 'BC'
},
{
offset: 14,
value: 'Canadá'
}
],
types: [
'locality',
'political',
'geocode'
]
},
{
description: 'Victorville, CA, EUA',
id: 'dd296d3fde2a539b9279cdd817c01183f69d07a7',
matched_substrings: [
{
length: 4,
offset: 0
}
],
place_id: 'ChIJedLdY1pkw4ARdjT0JVkRlQ0',
reference: 'ChIJedLdY1pkw4ARdjT0JVkRlQ0',
structured_formatting: {
main_text: 'Victorville',
main_text_matched_substrings: [
{
length: 4,
offset: 0
}
],
secondary_text: 'CA, EUA'
},
terms: [
{
offset: 0,
value: 'Victorville'
},
{
offset: 13,
value: 'CA'
},
{
offset: 17,
value: 'EUA'
}
],
types: [
'locality',
'political',
'geocode'
]
}
]
}
})
})

const response = await request(app)
.get('/cities?search=Vict')

expect(response.body.cities).toHaveLength(2)
})

it('should return an error when the google maps api request return an error message', async () => {
moxios.wait(() => {
const request = moxios.requests.mostRecent()
request.respondWith({
status: 200,
response: {
error_message: 'You have exceeded your daily request quota for this API.'
}
})
})

const response = await request(app)
.get('/cities?search=anycity')

expect(response.status).toBe(400)
})

it('should not return the cities if the search string is invalid', async () => {
const response = await request(app)
.get('/cities?search=')

expect(response.status).toBe(400)
})
})
})
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
}
},
"dependencies": {
"axios": "^0.19.0",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^8.1.0",
Expand All @@ -49,6 +50,7 @@
"@types/jest": "^24.0.18",
"@types/jsonwebtoken": "^8.3.4",
"@types/mongoose": "^5.5.19",
"@types/moxios": "^0.4.9",
"@types/supertest": "^2.0.8",
"@typescript-eslint/eslint-plugin": "^2.3.2",
"@typescript-eslint/parser": "^2.3.2",
Expand All @@ -67,6 +69,7 @@
"husky": "^3.0.8",
"jest": "^24.9.0",
"lint-staged": "^9.4.2",
"moxios": "^0.4.0",
"nodemon": "^1.19.3",
"prettier": "^1.18.2",
"sucrase": "^3.10.1",
Expand Down
3 changes: 3 additions & 0 deletions src/config/googleMaps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
placeUrl: 'https://maps.googleapis.com/maps/api/place/autocomplete/json'
}
43 changes: 43 additions & 0 deletions src/controllers/CityController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Request, Response } from 'express'
import * as Yup from 'yup'
import axios from 'axios'
import map from 'lodash/map'

import { GoogleMapPrediction } from '../types'
import googleMapsConfig from '../config/googleMaps'

class CityController {
async search (req: Request, res: Response): Promise<Response> {
const schema = Yup.string().required()

if (!(await schema.isValid(req.query.search))) {
return res.status(400).json({ error: 'Validation fails' })
}

try {
const response = await axios.get(googleMapsConfig.placeUrl, {
params: {
input: req.query.search,
types: '(cities)',
language: 'es_US',
key: process.env.GOOGLE_MAPS_API_KEY
}
})

if (response.data.error_message) {
return res.status(400).json({ error: response.data.error_message })
}

const normalizedCities = map(
response.data.predictions,
(prediction: GoogleMapPrediction) => prediction.description
)

return res.status(200).json({ cities: normalizedCities })
} catch (error) {
return res.status(400).json({ error: 'Unable to search cities' })
}
}
}

export default new CityController()
4 changes: 4 additions & 0 deletions src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import authMiddleware from './middlewares/auth'
import UserController from './controllers/UserController'
import AuthController from './controllers/AuthController'
import PostController from './controllers/PostController'
import CityController from './controllers/CityController'

const routes = Router()

Expand All @@ -14,6 +15,9 @@ routes.post('/login', AuthController.login)
// User
routes.post('/register', UserController.register)

// City
routes.get('/cities', CityController.search)

// Auth Middleware
routes.use(authMiddleware)

Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ import { Request } from 'express'
export interface AuthRequest extends Request {
userId: string
}

export interface GoogleMapPrediction {
description: string
}
34 changes: 33 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,13 @@
"@types/mongodb" "*"
"@types/node" "*"

"@types/moxios@^0.4.9":
version "0.4.9"
resolved "https://registry.yarnpkg.com/@types/moxios/-/moxios-0.4.9.tgz#64f5c067e0e0173f72944b785689420e04015b86"
integrity sha512-Sd1b24QRW2N194j2LEDPQAZK1h0TBtpN+2EIH+rERCgm38qm14JZwC7NlpE7n3jULhlCIPZBG8uNcbjF8KcCaQ==
dependencies:
axios "^0.19.0"

"@types/node@*", "@types/node@^12.0.2":
version "12.7.11"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.11.tgz#be879b52031cfb5d295b047f5462d8ef1a716446"
Expand Down Expand Up @@ -871,6 +878,14 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==

axios@^0.19.0:
version "0.19.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8"
integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==
dependencies:
follow-redirects "1.5.10"
is-buffer "^2.0.2"

babel-jest@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54"
Expand Down Expand Up @@ -1508,7 +1523,7 @@ [email protected], debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
dependencies:
ms "2.0.0"

[email protected]:
[email protected], debug@=3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
Expand Down Expand Up @@ -2323,6 +2338,13 @@ fn-name@~2.0.1:
resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7"
integrity sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=

[email protected]:
version "1.5.10"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
dependencies:
debug "=3.1.0"

for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
Expand Down Expand Up @@ -2910,6 +2932,11 @@ is-buffer@^1.1.5:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==

is-buffer@^2.0.2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623"
integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==

is-callable@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
Expand Down Expand Up @@ -4187,6 +4214,11 @@ mongoose@^5.7.3:
sift "7.0.1"
sliced "1.0.1"

moxios@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/moxios/-/moxios-0.4.0.tgz#fc0da2c65477d725ca6b9679d58370ed0c52f53b"
integrity sha1-/A2ixlR31yXKa5Z51YNw7QxS9Ts=

[email protected]:
version "0.6.0"
resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.6.0.tgz#aa922029fca4f0f641f360e74c5c1b6a4c47078e"
Expand Down

0 comments on commit 53cddbe

Please sign in to comment.