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

Organise review app middleware #3223

Merged
merged 9 commits into from
Feb 10, 2023
Merged

Organise review app middleware #3223

merged 9 commits into from
Feb 10, 2023

Conversation

colinrotherham
Copy link
Contributor

@colinrotherham colinrotherham commented Jan 30, 2023

We started organising our middleware into small exports for unit testing in 807f533

This PR adds a few more whilst I was working on the code

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-3223 January 30, 2023 20:34 Inactive
Copy link
Contributor

@36degrees 36degrees left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions unit testing as a rationale for the change – would it make sense for us to add unit tests for these files as we go?

Generally when code is moved around I find it a lot easier to review if the moves happen in a separate commit with minimal other changes.

const BANNER_COOKIE_NAME = 'dismissed-app-banner'

module.exports = function (app) {
// Detect if banner should be shown based on cookies set
app.use(cookieParser())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we split this change out into a separate commit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Done

cookies(),

// Turn form POSTs into data that can be used for validation
express.urlencoded({ extended: true })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we split this change out into a separate commit?

It looks like we no longer need body-parser because the functionality is now built into express – is that right? Would be good to capture in the commit message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Done

It looks like we no longer need body-parser because the functionality is now built into express – is that right?

Yeah, the express.urlencoded() middleware was added to Express.js in v4.16.0
https://expressjs.com/en/api.html#express.urlencoded

* Legacy query handling
*/
const locals = (req, res, next) => {
res.locals.legacy = ['1', 'true'].includes(req.query.legacy)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also consider splitting this refactor out into a separate commit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Done

I've configured Express.js with the standard URLSearchParams() too ready for Express.js v5

const { query } = req

// Check for query
query.has('example')

// Get query value
query.get(example')

// Set query value
query.set('example', 'value')

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that because of the change of the default query parser to simple?

I think the simple query parser would still work for our use case as we're not doing anything fancy with nested params etc. Do you think there's advantages to using URLSearchParams over it?

Copy link
Contributor Author

@colinrotherham colinrotherham Feb 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I remember that, there was a security vulnerability wasn't there

Primarily because we've now got the WHATWG URL and Fetch standards so it's all in Node.js too:

Query to string

// 'example1=value1&example2=value2'
req.query.toString()

Query to object

// { example1: 'value1', example2: 'value2' }
Object.fromEntries(req.query)

Query via URL object

const url = new URL('http://localhost')

url.search = '?example1=value1&example2=value2'

url.searchParams.get('example1') // 'value1'
url.searchParams.get('example2') // 'value2'

Express.js has said they'll also switch in future
expressjs/express#4990 (comment)

Happy to put it back to objects again

/**
* Request handling
*/
const request = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not 100% sure about this file as it's just bringing in middleware from dependencies?

Could we just include these in middleware/index.js instead?

Copy link
Contributor Author

@colinrotherham colinrotherham Feb 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's an option too

I'll explain my thinking in terms of testing GET or POST requests:

HTTP GET request

  1. Cookies are added to req.cookies
  2. Form submission req.body empty

HTTP POST request

  1. Cookies are added to req.cookies
  2. Form submission req.body populated

We're left with a nice way to test everything "HTTP request related" in one middleware

Hypothetically you'd put things like Content-Encoding gzip and application/json handling here too

import compression from 'compression'

export const request = [
  compression(),
  express.json(),
  express.urlencoded({
    extended: true
  })
]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added tests for this

@colinrotherham
Copy link
Contributor Author

@36degrees Sounds good

One commit per middleware, with a basic test per commit?

Thanks for taking a look

Base automatically changed from review-app-offline to main February 6, 2023 19:37
@36degrees
Copy link
Contributor

One commit per middleware, with a basic test per commit?

Sounds sensible 👍🏻 Doesn't have to be strict though – the main thing for me is to try and avoid moving and changing code in the same commit as it makes it harder to review.

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-3223 February 10, 2023 08:52 Inactive
@colinrotherham
Copy link
Contributor Author

colinrotherham commented Feb 10, 2023

@36degrees Tests added which found a few broken things

Let me know if you want them on a separate PR

  1. Component example back links don't append ?legacy=true
  2. Search example field names/values don't match JavaScript sort order
  3. Search example fields were only partially updated on submit (Organisation checkboxes)

@@ -338,21 +338,21 @@ describe(`http://localhost:${PORT}/full-page-examples/`, () => {
const body = await response.text()
const $ = cheerio.load(body)
// Check the results are correct
expect($.html()).toContain('822,411 results')
expect($.html()).toContain('121,842 results')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were building the seed string with:

// 'most-viewedundefinedundefined'
const seed = order + brexit + organisation

So these are newly-shuffled random totals using the query string instead:

// 'order=most-viewed'
const seed = query.toString()


// Make the total more readable
total: Number(randomizedTotal)
.toLocaleString('en', { useGrouping: true }),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where useGrouping (in en locale) adds commas to numbers

}
]
],
values: values["organisation"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@36degrees Your nice feature definitely saved a lot of code

Copy link
Contributor

@36degrees 36degrees left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tidy 👍🏻 Great to have those tests!

The `express.urlencoded()` middleware was added to Express.js in v4.16.0

https://expressjs.com/en/api.html#express.urlencoded
Consolidates request body and cookie parsing
The query `?legacy=true` is lost when clicking back
They were out of sync with the JavaScript and didn’t update correctly via query string
Include search text input and sort options in form so they’re submitted when the button is pressed
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-3223 February 10, 2023 14:44 Inactive
@colinrotherham colinrotherham merged commit 22d6ec3 into main Feb 10, 2023
@colinrotherham colinrotherham deleted the review-app-middleware branch February 10, 2023 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assurance consistency dependencies Pull requests that update a dependency file
Projects
Development

Successfully merging this pull request may close these issues.

4 participants