Skip to content

Commit 7ab07e6

Browse files
feat: Added a express/knex example application (#301)
Co-authored-by: James Sumners <[email protected]>
1 parent 2c00ab7 commit 7ab07e6

31 files changed

+1230
-0
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This repository contains example applications and scripts that demonstrate funct
1313
* [ESM](./esm-app) - example demonstrating how to load the agent in an [ESM](https://nodejs.org/api/esm.html) application. It also demonstrates how to register custom instrumentation for an ESM package.
1414
* [GraphQL Dataloader](./graphql-koa-dataloader) - example using Apollo Server, koa and GraphQL dataloader
1515
* [Kafkajs](./kafkajs) - example demonstrating [kafkajs](https://kafka.js.org/) with the Node.js agent
16+
* [Knex](./knex) - example demonstrating knex with the Node.js agent
1617
* [Mock Infinite Tracing Server](./mock-infinite-tracing-server) - mock gRPC server to use to locally test [infinite tracing](https://docs.newrelic.com/docs/distributed-tracing/infinite-tracing/introduction-infinite-tracing/) with a Node.js applciation
1718
* [Nest](./nestjs) - examples demonstrating Nestjs with the Node.js agent
1819
* [Next.js](./nextjs) - examples demonstrating Next.js with the Node.js agent

Diff for: knex/LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2018, Rob McLarty (http://robmclarty.com)
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
"Software"), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included
14+
in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Diff for: knex/README.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Knex/Express Example Application
2+
3+
This is an example app that uses the [New Relic hybrid agent](https://github.com/newrelic/newrelic-node-opentelemetry-integration) to demonstrate how to create both New Relic and OpenTelemetry spans.
4+
5+
6+
## Setup
7+
**Note**: This is used to demonstrate behavior between the New Relic Node.js agent and hybrid agent. The hybrid agent is currently only available to New Relic employees.
8+
9+
### Get hybrid agent
10+
11+
```sh
12+
git clone [email protected]:newrelic/newrelic-node-opentelemetry-integration.git
13+
npm install
14+
npm link
15+
```
16+
17+
```sh
18+
npm install
19+
cp env.sample .env
20+
# Fill out `NEW_RELIC_LICENSE_KEY`
21+
npm link @newrelic/opentelemetry-integration
22+
docker compose up -d
23+
npm run db:migrate
24+
npm run db:seed
25+
npm start
26+
```
27+
28+
## Exploring Telemetry
29+
More to come later...

Diff for: knex/config/database.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'use strict'
2+
3+
const env = process.env.NODE_ENV || 'development'
4+
const knexfile = require('../knexfile')
5+
const knex = require('knex')(knexfile[env])
6+
7+
module.exports = knex

Diff for: knex/db/migrations/20180326094647_create_users.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
exports.up = knex => {
2+
return knex.schema.createTable('users', t => {
3+
t.increments('id').primary().unsigned()
4+
t.string('username').unique().index()
5+
t.string('password')
6+
t.string('email').unique().index()
7+
t.timestamp('created_at').defaultTo(knex.fn.now())
8+
t.timestamp('updated_at').defaultTo(knex.fn.now())
9+
})
10+
}
11+
12+
exports.down = knex => {
13+
return knex.schema.dropTable('users')
14+
}

Diff for: knex/db/migrations/20180326105452_create_projects.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
exports.up = knex => {
2+
return knex.schema.createTable('projects', t => {
3+
t.increments('id').primary().unsigned()
4+
t.integer('user_id').references('users.id').unsigned().index().onDelete('CASCADE')
5+
t.string('name')
6+
t.text('description')
7+
t.timestamp('completed_at')
8+
t.timestamp('created_at').defaultTo(knex.fn.now())
9+
t.timestamp('updated_at').defaultTo(knex.fn.now())
10+
})
11+
}
12+
13+
exports.down = knex => {
14+
return knex.schema.dropTable('projects')
15+
}

Diff for: knex/db/seeds/001_users_seed.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict'
2+
3+
const { User } = require('../../server/models')
4+
5+
exports.seed = knex => knex(User.tableName).del()
6+
.then(() => [
7+
{
8+
username: 'admin',
9+
password: 'password',
10+
11+
},
12+
{
13+
username: 'first-user',
14+
password: 'another-password',
15+
16+
}
17+
])
18+
.then(newUsers => Promise.all(newUsers.map(user => User.create(user))))
19+
.catch(err => console.log('err: ', err))

Diff for: knex/db/seeds/002_project_seed.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use strict'
2+
3+
const { User, Project } = require('../../server/models')
4+
5+
exports.seed = knex => knex(Project.tableName).del()
6+
.then(() => User.findAll())
7+
.then(users => {
8+
if (users.length <= 0) throw 'No users found'
9+
10+
return users[0].id
11+
})
12+
.then(userId => [
13+
{
14+
user_id: userId,
15+
name: 'Sample Project',
16+
description: 'This is just a sample project to create some data to look at.'
17+
},
18+
{
19+
user_id: userId,
20+
name: 'Another Project',
21+
description: 'This is another project of sample data.',
22+
completed_at: knex.fn.now()
23+
}
24+
])
25+
.then(newProjects => Promise.all(newProjects.map(project => Project.create(project))))
26+
.catch(err => console.log('err: ', err))

Diff for: knex/docker-compose.yml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
version: '3'
2+
3+
services:
4+
db:
5+
container_name: pg_knex
6+
image: postgres:15
7+
ports:
8+
- "5436:5436"
9+
environment:
10+
PGPORT: 5436
11+
POSTGRES_PASSWORD: newrelic
12+
POSTGRES_DB: knex
13+
healthcheck:
14+
test: ["CMD", "pg_isready"]
15+
interval: 1s
16+
timeout: 10s
17+
retries: 30
18+

Diff for: knex/docs/index.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Knex Express Project Sample Documentation
2+
3+
## Usage
4+
5+
- [Auth](./usage/auth.md)
6+
- [Users](./usage/users.md)
7+
- [Projects](./usage/projects.md)

Diff for: knex/docs/usage/auth.md

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Authentication
2+
3+
This being a sample application, this is by no means a proper authentication
4+
implementation and is only meant to demonstrate some very basic concepts in
5+
the context of knex and express.
6+
7+
## Login
8+
9+
### Request
10+
11+
```shell
12+
curl \
13+
-X POST \
14+
-H "Content-Type: application/json" \
15+
-d '{"username":"admin", "password":"password"}' \
16+
http://localhost:3000/login
17+
```
18+
19+
### Response
20+
21+
```json
22+
{
23+
"ok": true,
24+
"message": "Login successful",
25+
"user": {
26+
"id": 1,
27+
"username": "admin",
28+
"email": "[email protected]",
29+
"created_at": "2018-04-03 14:43:02.183277-04",
30+
"updated_at": "2018-04-03 14:43:02.183277-04"
31+
}
32+
}
33+
```
34+
35+
## Register
36+
37+
```shell
38+
curl \
39+
-X POST \
40+
-H "Content-Type: application/json" \
41+
-d '{"username":"new-user", "password":"my-password", "email":"[email protected]"}' \
42+
http://localhost:3000/register
43+
```
44+
45+
### Response
46+
47+
```json
48+
{
49+
"ok": true,
50+
"message": "Registration successful",
51+
"user": {
52+
"id": 2,
53+
"username": "new-user",
54+
"email": "[email protected]",
55+
"created_at": "2018-04-03 14:43:02.183277-04",
56+
"updated_at": "2018-04-03 14:43:02.183277-04"
57+
}
58+
}
59+
```

Diff for: knex/docs/usage/projects.md

+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# Projects
2+
3+
Basic CRUD for interacting with the JSON API's project resources.
4+
5+
## Create
6+
7+
### Request
8+
9+
```shell
10+
curl \
11+
-X POST \
12+
-H "Content-Type: application/json" \
13+
-d '{"name":"my-project", "description":"This is my description of this project."}' \
14+
http://localhost:3000/users/1/projects
15+
```
16+
17+
### Response
18+
19+
```json
20+
{
21+
"ok": true,
22+
"message": "Project created",
23+
"project": {
24+
"id": 1,
25+
"name": "my-project",
26+
"description": "This is my description of this project.",
27+
"completed_at": null,
28+
"created_at": "2018-04-03 14:43:02.183277-04",
29+
"updated_at": "2018-04-03 14:43:02.183277-04"
30+
}
31+
}
32+
```
33+
34+
## List
35+
36+
### Request
37+
38+
```shell
39+
curl \
40+
-X GET \
41+
http://localhost:3000/users/1/projects
42+
```
43+
44+
### Response
45+
46+
```json
47+
{
48+
"ok": true,
49+
"message": "Projects found",
50+
"projects": [
51+
{
52+
"id": 1,
53+
"name": "my-project",
54+
"description": "This is my description of this project.",
55+
"completed_at": null,
56+
"created_at": "2018-04-03 14:43:02.183277-04",
57+
"updated_at": "2018-04-03 14:43:02.183277-04"
58+
},
59+
{
60+
"id": 2,
61+
"name": "my-other-project",
62+
"description": "This is my other project description.",
63+
"completed_at": "2018-04-03 14:43:02.183277-04",
64+
"created_at": "2018-04-03 14:43:02.183277-04",
65+
"updated_at": "2018-04-03 14:43:02.183277-04"
66+
}
67+
]
68+
}
69+
```
70+
71+
## Get
72+
73+
### Request
74+
75+
```shell
76+
curl \
77+
-X GET \
78+
http://localhost:3000/projects/1
79+
```
80+
81+
### Response
82+
83+
```json
84+
{
85+
"ok": true,
86+
"message": "Project found",
87+
"project": {
88+
"id": 1,
89+
"name": "my-project",
90+
"description": "This is my description of this project.",
91+
"completed_at": null,
92+
"created_at": "2018-04-03 14:43:02.183277-04",
93+
"updated_at": "2018-04-03 14:43:02.183277-04"
94+
}
95+
}
96+
```
97+
98+
## Update
99+
100+
### Request
101+
102+
```shell
103+
curl \
104+
-X PUT \
105+
-H "Content-Type: application/json" \
106+
-d '{"name":"my-new-name", "completed_at":"2018-04-03 14:43:02"}' \
107+
http://localhost:3000/projects/1
108+
```
109+
110+
### Response
111+
112+
```json
113+
{
114+
"ok": true,
115+
"message": "Project updated",
116+
"project": {
117+
"id": 1,
118+
"name": "my-new-name",
119+
"description": "This is my description of this project.",
120+
"completed_at": "2018-04-03 14:43:02.183277-04",
121+
"created_at": "2018-04-03 14:43:02.183277-04",
122+
"updated_at": "2018-04-03 14:43:02.183277-04"
123+
}
124+
}
125+
```
126+
127+
## Delete
128+
129+
### Request
130+
131+
```shell
132+
curl \
133+
-X DELETE \
134+
http://localhost:3000/projects/2
135+
```
136+
137+
### Response
138+
139+
```json
140+
{
141+
"ok": true,
142+
"message": "Project '2' deleted",
143+
"deleteCount": 1
144+
}
145+
```

0 commit comments

Comments
 (0)