Skip to content

Commit

Permalink
REST API example (#6634)
Browse files Browse the repository at this point in the history
* Adding REST API example

* Add smoke test for rest-api example

* Add changeset

* Update select field config
  • Loading branch information
JedWatson authored Sep 24, 2021
1 parent 50fda64 commit be039ec
Show file tree
Hide file tree
Showing 13 changed files with 695 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .changeset/gentle-colts-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@keystone-next/example-rest-api": major
"@keystonejs/examples-smoke-tests": patch
---

REST API example
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ jobs:
'default-values.test.ts',
'extend-graphql-schema.test.ts',
'json.test.ts',
'rest-api.test.ts',
'roles.test.ts',
'task-manager.test.ts',
'testing.test.ts',
Expand Down
1 change: 1 addition & 0 deletions examples/rest-api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# @keystone-next/example-rest-api
17 changes: 17 additions & 0 deletions examples/rest-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Feature Example - Creating REST API endpoints

This project demonstrates how to create REST endpoints by extending Keystone's express app and using the Query API to execute queries against the schema.

## Instructions

To run this project, clone the Keystone repository locally then navigate to this directory and run:

```shell
yarn dev
```

This will start the Admin UI at [localhost:3000](http://localhost:3000).

You can use the Admin UI to create items in your database.

To run the seed data script, pass the `--seed-data` flag when starting the app.
42 changes: 42 additions & 0 deletions examples/rest-api/keystone.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { config } from '@keystone-next/keystone';
import { lists } from './schema';
import { insertSeedData } from './seed-data';
import { getTasks } from './routes/tasks';

/*
A quick note on types: normally if you're adding custom properties to your
express request you'd extend the global Express namespace, but we're not
doing that here because we're in the keystone monorepo; so we're casting
the request and keystone context with `as` instead to keep this local.
*/

export default config({
db: {
provider: 'sqlite',
url: process.env.DATABASE_URL || 'file:./keystone-example.db',
async onConnect(context) {
if (process.argv.includes('--seed-data')) {
await insertSeedData(context);
}
},
},
server: {
/*
This is the main part of this example. Here we include a function that
takes the express app Keystone created, and does two things:
- Adds a middleware function that will run on requests matching our REST
API routes, to get a keystone context on `req`. This means we don't
need to put our route handlers in a closure and repeat it for each.
- Adds a GET handler for tasks, which will query for tasks in the
Keystone schema and return the results as JSON
*/
extendExpressApp: (app, createContext) => {
app.use('/rest', async (req, res, next) => {
(req as any).context = await createContext(req, res);
next();
});
app.get('/rest/tasks', getTasks);
},
},
lists,
});
23 changes: 23 additions & 0 deletions examples/rest-api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@keystone-next/example-rest-api",
"version": "0.0.0",
"private": true,
"license": "MIT",
"scripts": {
"dev": "keystone-next dev",
"start": "keystone-next start",
"build": "keystone-next build",
"seed-data": "keystone-next --seed-data"
},
"dependencies": {
"@keystone-next/keystone": "^25.0.0",
"express": "^4.17.1"
},
"devDependencies": {
"typescript": "^4.4.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
},
"repository": "https://github.com/keystonejs/keystone/tree/master/examples/rest-api"
}
42 changes: 42 additions & 0 deletions examples/rest-api/routes/tasks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { Request, Response } from 'express';
import type { KeystoneContext } from '@keystone-next/keystone/types';

/*
This example route handler gets all the tasks in the database and returns
them as JSON data, emulating what you'd normally do in a REST API.
More sophisticated API routes might accept query params to select fields,
map more params to `where` arguments, add pagination support, etc.
We're also demonstrating how you can query related data through the schema.
*/

export async function getTasks(req: Request, res: Response) {
// This was added by the context middleware in ../keystone.ts
const context = (req as any).context as KeystoneContext;
// Let's map the `complete` query param to a where filter
let isComplete;
if (req.query.complete === 'true') {
isComplete = { equals: true };
} else if (req.query.complete === 'false') {
isComplete = { equals: false };
}
// Now we can use it to query the Keystone Schema
const users = await context.query.Task.findMany({
where: {
isComplete,
},
query: `
id
label
priority
isComplete
assignedTo {
id
name
}
`,
});
// And return the result as JSON
res.json(users);
}
Loading

0 comments on commit be039ec

Please sign in to comment.