Skip to content

fix: add longitude, latitude, and timezone to RequestData.geo #1777

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

Merged
merged 11 commits into from
Nov 18, 2022
11 changes: 11 additions & 0 deletions cypress/integration/middleware/enhanced.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,15 @@ describe('Enhanced middleware', () => {
.that.includes('This was static but has been transformed in')
})
})

it('adds geo data', () => {
cy.request('/api/geo').then((response) => {
expect(response.body).to.have.nested.property('headers.x-geo-country')
expect(response.body).to.have.nested.property('headers.x-geo-region')
expect(response.body).to.have.nested.property('headers.x-geo-city')
expect(response.body).to.have.nested.property('headers.x-geo-longitude')
expect(response.body).to.have.nested.property('headers.x-geo-latitude')
expect(response.body).to.have.nested.property('headers.x-geo-timezone')
})
})
})
15 changes: 12 additions & 3 deletions demos/middleware/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

import { MiddlewareRequest } from '@netlify/next'
import { MiddlewareRequest, NextRequest } from '@netlify/next'

export async function middleware(req: NextRequest) {
let response
Expand Down Expand Up @@ -29,6 +27,17 @@ export async function middleware(req: NextRequest) {
return request.next()
}

if (pathname.startsWith('/api/geo')) {
req.headers.set('x-geo-country', req.geo.country)
req.headers.set('x-geo-region', req.geo.region)
req.headers.set('x-geo-city', req.geo.city)
req.headers.set('x-geo-longitude', req.geo.longitude)
req.headers.set('x-geo-latitude', req.geo.latitude)
req.headers.set('x-geo-timezone', req.geo.timezone)

return request.next()
}

if (pathname.startsWith('/headers')) {
// Add a header to the rewritten request
req.headers.set('x-hello', 'world')
Expand Down
3 changes: 3 additions & 0 deletions demos/middleware/pages/api/geo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function handler(req, res) {
res.status(200).json({ name: 'geo-test', headers: req.headers })
}
15 changes: 14 additions & 1 deletion packages/next/src/middleware/request.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import type { NextURL } from 'next/dist/server/web/next-url'
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import type { NextRequest as InternalNextRequest } from 'next/server'

import { MiddlewareResponse } from './response'

export type NextRequest = InternalNextRequest & {
get geo():
| {
city?: string
country?: string
region?: string
latitude?: string
longitude?: string
timezone?: string
}
| undefined
}

export interface NextOptions {
/**
* Include conditional request headers in the request to the origin.
Expand Down
6 changes: 6 additions & 0 deletions packages/next/test/request.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ describe('MiddlewareRequest', () => {
code: chance.province(),
},
city: chance.city(),
latitude: chance.latitude(),
longitude: chance.longitude(),
timezone: chance.timezone(),
},
ip,
}
Expand All @@ -33,6 +36,9 @@ describe('MiddlewareRequest', () => {
country: context.geo.country?.code,
region: context.geo.subdivision?.code,
city: context.geo.city,
latitude: context.geo.latitude?.toString(),
longitude: context.geo.longitude?.toString(),
timezone: context.geo.timezone,
}

const req = new URL(url)
Expand Down
5 changes: 4 additions & 1 deletion packages/runtime/src/templates/edge/next-dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,14 @@ const handler = async (req, context) => {
return
}

// This is the format expected by Next.js
// This is the format expected by Next.js along with the timezone which we support.
const geo = {
country: context.geo.country?.code,
region: context.geo.subdivision?.code,
city: context.geo.city,
latitude: context.geo.latitude?.toString(),
longitude: context.geo.longitude?.toString(),
timezone: context.geo.timezone,
}

// A default request id is fine locally
Expand Down
6 changes: 5 additions & 1 deletion packages/runtime/src/templates/edge/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface RequestData {
region?: string
latitude?: string
longitude?: string
timezone?: string
}
headers: Record<string, string>
ip?: string
Expand Down Expand Up @@ -63,10 +64,13 @@ const handler = async (req: Request, context: Context) => {
return
}

const geo = {
const geo: RequestData['geo'] = {

Choose a reason for hiding this comment

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

Yay type!

country: context.geo.country?.code,
region: context.geo.subdivision?.code,
city: context.geo.city,
latitude: context.geo.latitude?.toString(),
longitude: context.geo.longitude?.toString(),
timezone: context.geo.timezone,
}

const requestId = req.headers.get('x-nf-request-id')
Expand Down