-
Notifications
You must be signed in to change notification settings - Fork 87
feat: split api routes into separate functions #1495
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
Changes from 24 commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
25f3e2f
feat: add static analysis helper
ascorbic fbfd0cc
feat: split api routes into separate functions
ascorbic 57b31b2
chore: fix syntax of api handlers for better static analysis
ascorbic dc8c3de
fix: broken test
ascorbic 47f0a95
Merge branch 'main' into mk/background-functions
ascorbic 9d1dfdd
chore: change config shape
ascorbic b3cc08e
Merge branch 'mk/background-functions' of github.com:netlify/netlify-…
ascorbic 1786f84
chore: fix test
ascorbic 8f312f1
chore: windows paths :angry:
ascorbic 5f582b2
chore: add e2e tests for extended API routes
ascorbic 56abd3a
Merge branch 'main' into mk/background-functions
ascorbic 00a80a7
chore: fix cypress 404 test
ascorbic c266478
chore: fix import
ascorbic 59e5607
Merge branch 'main' into mk/background-functions
ascorbic 6b5c991
Merge branch 'main' into mk/background-functions
ascorbic c1fc1be
chore: lint
ascorbic bc662f8
Merge branch 'main' into mk/background-functions
ascorbic bb65d50
chore: remove unused function
ascorbic daeb493
Merge branch 'main' into mk/background-functions
ascorbic 6aad6b1
chore: use enum for api route type
ascorbic df28822
Merge branch 'main' into mk/background-functions
ascorbic 7cbe3ef
chore: snapidoo
ascorbic 56d5a06
chore: lockfile
ascorbic 0d3152f
chore: debug preview test
ascorbic f83d562
chore: use const enum
ascorbic 8305373
Merge branch 'main' into mk/background-functions
ascorbic 5354005
Merge branch 'main' into mk/background-functions
ascorbic 898a8a7
feat: add warning logs for advanced api routes
ascorbic a190160
Merge branch 'main' into mk/background-functions
ascorbic 781be0c
chore: support jsx
ascorbic File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
describe('Extended API routes', () => { | ||
it('returns HTTP 202 Accepted for background route', () => { | ||
cy.request('/api/hello-background').then((response) => { | ||
expect(response.status).to.equal(202) | ||
}) | ||
}) | ||
it('correctly returns 404 for scheduled route', () => { | ||
cy.request({ url: '/api/hello-scheduled', failOnStatusCode: false }).its('status').should('equal', 404) | ||
}) | ||
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export default (req, res) => { | ||
res.setHeader('Content-Type', 'application/json') | ||
res.status(200) | ||
res.json({ message: 'hello world :)' }) | ||
} | ||
|
||
export const config = { | ||
type: 'experimental-background', | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export default (req, res) => { | ||
res.setHeader('Content-Type', 'application/json') | ||
res.status(200) | ||
res.json({ message: 'hello world :)' }) | ||
} | ||
|
||
export const config = { | ||
type: 'experimental-scheduled', | ||
schedule: '@hourly', | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import fs from 'fs' | ||
|
||
import { extractExportedConstValue, UnsupportedValueError } from 'next/dist/build/analysis/extract-const-value' | ||
import { parseModule } from 'next/dist/build/analysis/parse-module' | ||
import { relative } from 'pathe' | ||
|
||
// I have no idea what eslint is up to here but it gives an error | ||
nickytonline marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// eslint-disable-next-line no-shadow | ||
export enum ApiRouteType { | ||
ascorbic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
SCHEDULED = 'experimental-scheduled', | ||
BACKGROUND = 'experimental-background', | ||
} | ||
|
||
export interface ApiStandardConfig { | ||
nickytonline marked this conversation as resolved.
Show resolved
Hide resolved
|
||
type?: never | ||
runtime?: 'nodejs' | 'experimental-edge' | ||
schedule?: never | ||
} | ||
|
||
export interface ApiScheduledConfig { | ||
type: ApiRouteType.SCHEDULED | ||
runtime?: 'nodejs' | ||
schedule: string | ||
} | ||
|
||
export interface ApiBackgroundConfig { | ||
type: ApiRouteType.BACKGROUND | ||
runtime?: 'nodejs' | ||
schedule?: never | ||
} | ||
|
||
export type ApiConfig = ApiStandardConfig | ApiScheduledConfig | ApiBackgroundConfig | ||
|
||
export const validateConfigValue = (config: ApiConfig, apiFilePath: string): config is ApiConfig => { | ||
if (config.type === ApiRouteType.SCHEDULED) { | ||
if (!config.schedule) { | ||
console.error( | ||
`Invalid config value in ${relative(process.cwd(), apiFilePath)}: schedule is required when type is "${ | ||
ApiRouteType.SCHEDULED | ||
}"`, | ||
) | ||
return false | ||
} | ||
if ((config as ApiConfig).runtime === 'experimental-edge') { | ||
nickytonline marked this conversation as resolved.
Show resolved
Hide resolved
|
||
console.error( | ||
`Invalid config value in ${relative( | ||
process.cwd(), | ||
apiFilePath, | ||
)}: edge runtime is not supported for scheduled functions`, | ||
) | ||
return false | ||
} | ||
return true | ||
} | ||
|
||
if (!config.type || config.type === ApiRouteType.BACKGROUND) { | ||
if (config.schedule) { | ||
console.error( | ||
`Invalid config value in ${relative(process.cwd(), apiFilePath)}: schedule is not allowed unless type is "${ | ||
ApiRouteType.SCHEDULED | ||
}"`, | ||
) | ||
return false | ||
} | ||
if (config.type && (config as ApiConfig).runtime === 'experimental-edge') { | ||
console.error( | ||
`Invalid config value in ${relative( | ||
process.cwd(), | ||
apiFilePath, | ||
)}: edge runtime is not supported for background functions`, | ||
) | ||
return false | ||
} | ||
return true | ||
} | ||
console.error( | ||
`Invalid config value in ${relative(process.cwd(), apiFilePath)}: type ${ | ||
(config as ApiConfig).type | ||
} is not supported`, | ||
) | ||
return false | ||
} | ||
|
||
/** | ||
* Uses Next's swc static analysis to extract the config values from a file. | ||
*/ | ||
export const extractConfigFromFile = async (apiFilePath: string): Promise<ApiConfig> => { | ||
const fileContent = await fs.promises.readFile(apiFilePath, 'utf8') | ||
// No need to parse if there's no "config" | ||
if (!fileContent.includes('config')) { | ||
return {} | ||
} | ||
const ast = await parseModule(apiFilePath, fileContent) | ||
|
||
let config: ApiConfig | ||
try { | ||
config = extractExportedConstValue(ast, 'config') | ||
} catch (error) { | ||
if (error instanceof UnsupportedValueError) { | ||
console.warn(`Unsupported config value in ${relative(process.cwd(), apiFilePath)}`) | ||
} | ||
return {} | ||
} | ||
if (validateConfigValue(config, apiFilePath)) { | ||
return config | ||
} | ||
throw new Error(`Unsupported config value in ${relative(process.cwd(), apiFilePath)}`) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these debug lines still necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just following up on this @ascorbic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Last ping about this. It's not a blocker, but I assume it was only for debugging purposes?