Skip to content

Commit

Permalink
[with-typescript] Updated TypeScript example to use API routes
Browse files Browse the repository at this point in the history
Next.js 9.0.0 has been out for a while, which supports API routes, but
the examples were never updated to make use of it. This PR adds a simple
example of an API route which also makes use of dynamic routing.

A simple `fetch()` wrapper is also added for example purposes, and the
pages structure have also been updated to dynamic routing.
  • Loading branch information
resir014 committed Oct 14, 2019
1 parent b2adfde commit c8fdb91
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 49 deletions.
4 changes: 2 additions & 2 deletions examples/with-typescript/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ const Layout: React.FunctionComponent<Props> = ({
<a>About</a>
</Link>{' '}
|{' '}
<Link href="/initial-props">
<a>With Initial Props</a>
<Link href="/users">
<a>Users List</a>
</Link>
</nav>
</header>
Expand Down
2 changes: 1 addition & 1 deletion examples/with-typescript/components/ListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type Props = {
}

const ListItem: React.FunctionComponent<Props> = ({ data }) => (
<Link href={`/detail?id=${data.id}`}>
<Link href={`/users/${data.id}`}>
<a>
{data.id}: {data.name}
</a>
Expand Down
1 change: 1 addition & 0 deletions examples/with-typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"type-check": "tsc"
},
"dependencies": {
"isomorphic-unfetch": "3.0.0",
"next": "latest",
"react": "^16.10.1",
"react-dom": "^16.10.1"
Expand Down
18 changes: 18 additions & 0 deletions examples/with-typescript/pages/api/users/[id].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { sampleUserData } from '../../../utils/sample-data'

export default (req: NextApiRequest, res: NextApiResponse) => {
try {
const { id } = req.query;
const selected = sampleUserData.find(data => data.id === Number(id))

if (!selected) {
throw new Error('Cannot find user')
}

res.status(200).json(selected)
} catch (err) {
res.status(404).json({ statusCode: 404, message: err.message })
}
}

14 changes: 14 additions & 0 deletions examples/with-typescript/pages/api/users/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { sampleUserData } from '../../../utils/sample-data'

export default (_: NextApiRequest, res: NextApiResponse) => {
try {
if (!Array.isArray(sampleUserData)) {
throw new Error('Cannot find user data')
}

res.status(200).json(sampleUserData)
} catch (err) {
res.status(500).json({ statusCode: 500, message: err.message })
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as React from 'react'
import { NextPageContext } from 'next'
import Layout from '../components/Layout'
import { User } from '../interfaces'
import { findData } from '../utils/sample-api'
import ListDetail from '../components/ListDetail'

import { User } from '../../interfaces'
import Layout from '../../components/Layout'
import ListDetail from '../../components/ListDetail'
import { sampleFetchWrapper } from '../../utils/sample-api'

type Props = {
item?: User
Expand All @@ -14,7 +15,7 @@ class InitialPropsDetail extends React.Component<Props> {
static getInitialProps = async ({ query }: NextPageContext) => {
try {
const { id } = query
const item = await findData(Array.isArray(id) ? id[0] : id)
const item = await sampleFetchWrapper(`http://localhost:3000/api/users/${Array.isArray(id) ? id[0] : id}`)
return { item }
} catch (err) {
return { errors: err.message }
Expand All @@ -36,7 +37,7 @@ class InitialPropsDetail extends React.Component<Props> {

return (
<Layout
title={`${item ? item.name : 'Detail'} | Next.js + TypeScript Example`}
title={`${item ? item.name : 'User Detail'} | Next.js + TypeScript Example`}
>
{item && <ListDetail item={item} />}
</Layout>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { NextPage } from 'next'
import Link from 'next/link'
import Layout from '../components/Layout'
import List from '../components/List'
import { User } from '../interfaces'
import { findAll } from '../utils/sample-api'

import Layout from '../../components/Layout'
import List from '../../components/List'
import { User } from '../../interfaces'
import { sampleFetchWrapper } from '../../utils/sample-api'

type Props = {
items: User[]
pathname: string
}

const WithInitialProps: NextPage<Props> = ({ items, pathname }) => (
<Layout title="List Example (as Functional Component) | Next.js + TypeScript Example">
<h1>List Example (as Function Component)</h1>
<Layout title="Users List | Next.js + TypeScript Example">
<h1>Users List</h1>
<p>
Example fetching data from inside <code>getInitialProps()</code>.
</p>
<p>You are currently on: {pathname}</p>
<List items={items} />
<p>
Expand All @@ -24,10 +28,12 @@ const WithInitialProps: NextPage<Props> = ({ items, pathname }) => (
)

WithInitialProps.getInitialProps = async ({ pathname }) => {
// Example for including initial props in a Next.js function compnent page.
// Example for including initial props in a Next.js function component page.
// Don't forget to include the respective types for any props passed into
// the component.
const items: User[] = await findAll()
const items: User[] = await sampleFetchWrapper(
'http://localhost:3000/api/users'
)

return { items, pathname }
}
Expand Down
43 changes: 11 additions & 32 deletions examples/with-typescript/utils/sample-api.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,13 @@
import { User } from '../interfaces'

/** Dummy user data. */
export const dataArray: User[] = [
{ id: 101, name: 'Alice' },
{ id: 102, name: 'Bob' },
{ id: 103, name: 'Caroline' },
{ id: 104, name: 'Dave' },
]

/**
* Calls a mock API which finds a user by ID from the list above.
*
* Throws an error if not found.
*/
export async function findData(id: number | string) {
const selected = dataArray.find(data => data.id === Number(id))

if (!selected) {
throw new Error('Cannot find user')
}

return selected
}

/** Calls a mock API which returns the above array to simulate "get all". */
export async function findAll() {
// Throw an error, just for example.
if (!Array.isArray(dataArray)) {
throw new Error('Cannot find users')
import fetch from 'isomorphic-unfetch'

export async function sampleFetchWrapper(
input: RequestInfo,
init?: RequestInit
) {
try {
const data = await fetch(input, init).then(res => res.json())
return data
} catch (err) {
throw new Error(err.message)
}

return dataArray
}
9 changes: 9 additions & 0 deletions examples/with-typescript/utils/sample-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { User } from '../interfaces'

/** Dummy user data. */
export const sampleUserData: User[] = [
{ id: 101, name: 'Alice' },
{ id: 102, name: 'Bob' },
{ id: 103, name: 'Caroline' },
{ id: 104, name: 'Dave' },
]

0 comments on commit c8fdb91

Please sign in to comment.