Skip to content

Commit

Permalink
feat: landing page (#1478)
Browse files Browse the repository at this point in the history
* feat: landing page

* revert this lol

* simplify test cases

* chore: add a tutorial link
  • Loading branch information
n1ru4l committed Jul 28, 2022
1 parent b4a1f1c commit f325429
Show file tree
Hide file tree
Showing 11 changed files with 631 additions and 121 deletions.
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

0 comments on commit f325429

Please sign in to comment.