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

feat: landing page #1478

Merged
merged 4 commits into from
Jul 28, 2022
Merged
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
2 changes: 1 addition & 1 deletion examples/koa/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { buildApp } from './app.js'
import { buildApp } from './app'

const app = buildApp()

Expand Down
2 changes: 2 additions & 0 deletions packages/graphql-yoga/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
src/graphiql-html.ts
src/landing-page-html.ts
97 changes: 76 additions & 21 deletions packages/graphql-yoga/__tests__/node.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1397,33 +1397,88 @@ describe('Browser', () => {
})
})

it('should return 404 if request path does not match with the defined endpoint', async () => {
const hostname = '127.0.0.1'
const port = 4000 + Math.floor(Math.random() * 1000)
const endpoint = '/mypath'
const yoga = createYoga({
graphqlEndpoint: endpoint,
logging: false,
describe('404 Handling', () => {
it('returns 404 if request path does not match with the defined graphql endpoint (POST)', async () => {
const yoga = createYoga({
logging: false,
})
const url = `http://localhost:4000/notgraphql`
const response = await yoga.fetch(
url + '?query=' + encodeURIComponent('{ __typename }'),
)

expect(response.status).toEqual(404)
expect(await response.text()).toEqual('')
})
const server = createServer(yoga)
const url = `http://${hostname}:${port}${endpoint}`
try {
await new Promise<void>((resolve) =>
server.listen(port, hostname, () => resolve()),
it('returns 404 if request path does not match with the defined graphql endpoint (GET)', async () => {
const yoga = createYoga({
logging: false,
})
const url = `http://localhost:4000/notgraphql`
const response = await yoga.fetch(
url.replace('mypath', 'yourpath') +
'?query=' +
encodeURIComponent('{ __typename }'),
{ method: 'GET' },
)
const response = await fetch(

expect(response.status).toEqual(404)
expect(await response.text()).toEqual('')
})
it('returns 404 with landing page when accepting text/html and sending a GET request', async () => {
const yoga = createYoga({
logging: false,
})
const url = `http://localhost:4000/notgraphql`
const response = await yoga.fetch(
url + '?query=' + encodeURIComponent('{ __typename }'),
{ method: 'GET', headers: { Accept: 'text/html' } },
)
expect(response.status).toEqual(200)
const response2 = await fetch(

expect(response.status).toEqual(404)
const body = await response.text()
expect(body).toContain('<!DOCTYPE html>')
expect(body).toContain('GraphQL Yoga')
})
it('returns 404 without landing page when accepting text/html and sending a GET request but disabled landing page', async () => {
const yoga = createYoga({
logging: false,
landingPage: false,
})
const url = `http://localhost:4000/notgraphql`
const response = await yoga.fetch(
url.replace('mypath', 'yourpath') +
'?query=' +
encodeURIComponent('{ __typename }'),
{ method: 'GET', headers: { Accept: 'text/html' } },
)
expect(response2.status).toEqual(404)
} finally {
await new Promise<void>((resolve, reject) =>
server.close((err) => (err ? reject(err) : resolve())),
)
}

expect(response.status).toEqual(404)
const body = await response.text()
expect(body).toEqual('')
})
it('404 handling does allow defining different route handlers', async () => {
const yoga = createYoga({
logging: false,
plugins: [
{
onRequest({ request, endResponse, fetchAPI }) {
if (request.url.endsWith('/iliketurtles')) {
endResponse(
new fetchAPI.Response('Do you really like em?', {
status: 666,
}),
)
}
},
},
],
})
const url = `http://localhost:4000/iliketurtles`
const response = await yoga.fetch(url)

expect(response.status).toEqual(666)
const body = await response.text()
expect(body).toEqual('Do you really like em?')
})
})
14 changes: 0 additions & 14 deletions packages/graphql-yoga/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,6 @@
"default": "./dist/esm/index.js"
}
},
"./*": {
"require": {
"types": "./dist/typings/*.d.ts",
"default": "./dist/cjs/*.js"
},
"import": {
"types": "./dist/typings/*.d.ts",
"default": "./dist/esm/*.js"
},
"default": {
"types": "./dist/typings/*.d.ts",
"default": "./dist/esm/*.js"
}
},
"./package.json": "./package.json"
},
"typings": "dist/typings/index.d.ts",
Expand Down
57 changes: 38 additions & 19 deletions packages/graphql-yoga/scripts/generate-graphiql-html.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,58 @@
import { minify } from 'html-minifier-terser'
import { minify as minifyT } from 'html-minifier-terser'
import * as fs from 'fs'
import * as path from 'path'
import { fileURLToPath } from 'url'

const __dirname = path.dirname(fileURLToPath(import.meta.url))

async function main() {
async function minify(str) {
return (
await minifyT(str, {
minifyJS: true,
useShortDoctype: false,
removeAttributeQuotes: true,
collapseWhitespace: true,
minifyCSS: true,
})
).toString('utf-8')
}

async function minifyGraphiQLHTML() {
const graphiqlVersion = JSON.parse(
fs.readFileSync(
path.join(__dirname, '..', '..', 'graphiql', 'package.json'),
'utf-8',
),
).version

const minified = (
await minify(
fs
.readFileSync(
path.join(__dirname, '..', 'src', 'graphiql.html'),
'utf-8',
)
.replace(/__GRAPHIQL_VERSION__/g, graphiqlVersion),
{
minifyJS: true,
useShortDoctype: false,
removeAttributeQuotes: true,
collapseWhitespace: true,
},
)
).toString('utf-8')
const minified = await minify(
fs
.readFileSync(path.join(__dirname, '..', 'src', 'graphiql.html'), 'utf-8')
.replace(/__GRAPHIQL_VERSION__/g, graphiqlVersion),
)

fs.writeFileSync(
path.join(__dirname, '../src/graphiqlHTML.ts'),
path.join(__dirname, '../src/graphiql-html.ts'),
`export default ${JSON.stringify(minified)}`,
)
}

async function minifyLandingPageHTML() {
const minified = await minify(
fs.readFileSync(
path.join(__dirname, '..', 'src', 'landing-page.html'),
'utf-8',
),
)

fs.writeFileSync(
path.join(__dirname, '../src/landing-page-html.ts'),
`export default ${JSON.stringify(minified)}`,
)
}

async function main() {
await Promise.all([minifyGraphiQLHTML(), minifyLandingPageHTML()])
}

main()
1 change: 0 additions & 1 deletion packages/graphql-yoga/src/graphiqlHTML.ts

This file was deleted.

Loading