Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
module.exports = {
env: {
node: true,
commonjs: true,
es2020: true,
es6: true,
},
extends: ['eslint:recommended', 'plugin:prettier/recommended'],
parserOptions: {
ecmaVersion: 11,
},
parserOptions: {},
plugins: ['prettier'],
rules: {},
overrides: [
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.vscode
coverage
apidoc
dist-api

#docker generated files
data/pg
Expand Down
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
14.5.0
137 changes: 134 additions & 3 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

- [PingAPI](#PingAPI)
- [Root path, ping](#Root-path,-ping)
- [ProfileAPI](#ProfileAPI)
- [Request List of Profiles](#Request-List-of-Profiles)
- [Request User information](#Request-User-information)
- [UserAPI](#UserAPI)
- [Request List of Users](#Request-List-of-Users)
- [Request User information](#Request-User-information)
Expand Down Expand Up @@ -39,6 +42,129 @@ HTTP/1.1 200 OK
}
```

# <a name='ProfileAPI'></a> ProfileAPI

## <a name='Request-List-of-Profiles'></a> Request List of Profiles
[Back to top](#top)

```
GET /profile/
```

### Examples
Example usage:

```curl
curl -i http://localhost:8000/profiles
```

### Success response

#### Success response - `Success 200`

| Name | Type | Description |
|----------|------------|---------------------------------------|
| id | `UUID` | <p>Unique id of the Profile.</p> |
| name | `String` | <p>Name of the Profile.</p> |
| email | `String` | <p>Email of the Profile.</p> |
| avatar | `String` | <p>Avatar url for the Profile.</p> |

### Success response example

#### Success response example - `Success-Response:`

```json
HTTP/1.1 200 OK
[
{
"id": "013e4ab9-77e0-48de-9efe-4d96542e791f",
"name": "Frank Martinez",
"email": "frank@example.com",
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/hermanobrother/128.jpg"
},
{
"id": "013e4ab9-77e0-48de-9efe-4d96542e791f",
"name": "Cathy Warmund",
"email": "cathy@example.com",
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/geneseleznev/128.jpg"
}
]
```

## <a name='Request-User-information'></a> Request User information
[Back to top](#top)

```
GET /profile/:id
```

### Parameters - `Parameter`

| Name | Type | Description |
|----------|------------|---------------------------------------|
| id | `UUID` | <p>Profile's unique ID.</p> |

### Examples
Example usage:

```curl
curl -i http://localhost:3000/Profile/013e4ab9-77e0-48de-9efe-4d96542e791f
```

### Success response

#### Success response - `Success 200`

| Name | Type | Description |
|----------|------------|---------------------------------------|
| id | `UUID` | <p>Unique id of the Profile.</p> |
| name | `String` | <p>Name of the Profile.</p> |
| email | `String` | <p>Email of the Profile.</p> |
| avatar | `String` | <p>Avatar url for the Profile.</p> |

### Success response example

#### Success response example - `Success-Response:`

```json
HTTP/1.1 200 OK
{
"id": "013e4ab9-77e0-48de-9efe-4d96542e791f",
"name": "Frank Martinez",
"email": "frank@example.com",
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/hermanobrother/128.jpg"
}
```

### Error response

#### Error response - `Error 4xx`

| Name | Type | Description |
|----------|------------|---------------------------------------|
| ProfileNotFound | | <p>404 The id of the Profile was not found.</p> |
| InvalidAuthentication | | <p>403 Authentication failed.</p> |

### Error response example

#### Error response example - `ProfileNotFound:`

```json
HTTP/1.1 404 Not Found
{
"error": "ProfileNotFound"
}
```

#### Error response example - `Forbidden:`

```json
HTTP/1.1 403 Forbidden
{
"error": "Authorization failed"
}
```

# <a name='UserAPI'></a> UserAPI

## <a name='Request-List-of-Users'></a> Request List of Users
Expand All @@ -64,6 +190,7 @@ curl -i http://localhost:8000/users
| id | `UUID` | <p>Unique id of the User.</p> |
| name | `String` | <p>Name of the User.</p> |
| email | `String` | <p>Email of the User.</p> |
| avatar | `String` | <p>Avatar url for the User.</p> |

### Success response example

Expand All @@ -75,12 +202,14 @@ HTTP/1.1 200 OK
{
"id": "013e4ab9-77e0-48de-9efe-4d96542e791f",
"name": "Frank Martinez",
"email": "frank@example.com"
"email": "frank@example.com",
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/hermanobrother/128.jpg"
},
{
"id": "013e4ab9-77e0-48de-9efe-4d96542e791f",
"name": "Cathy Warmund",
"email": "cathy@example.com"
"email": "cathy@example.com",
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/geneseleznev/128.jpg"
}
]
```
Expand Down Expand Up @@ -114,6 +243,7 @@ curl -i http://localhost:3000/user/013e4ab9-77e0-48de-9efe-4d96542e791f
| id | `UUID` | <p>Unique id of the User.</p> |
| name | `String` | <p>Name of the User.</p> |
| email | `String` | <p>Email of the User.</p> |
| avatar | `String` | <p>Avatar url for the User.</p> |

### Success response example

Expand All @@ -124,7 +254,8 @@ HTTP/1.1 200 OK
{
"id": "013e4ab9-77e0-48de-9efe-4d96542e791f",
"name": "Frank Martinez",
"email": "frank@example.com"
"email": "frank@example.com",
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/hermanobrother/128.jpg"
}
```

Expand Down
50 changes: 0 additions & 50 deletions __tests__/routes/users.test.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const request = require('supertest');
import request from 'supertest';
// Full app so we can test the 404
const server = require('../../api/app.js');
import server from '../../app';

describe('index router endpoints', () => {
beforeAll(() => {});
Expand All @@ -17,7 +17,7 @@ describe('index router endpoints', () => {
const res = await request(server).get('/ping');

expect(res.status).toBe(404);
expect(res.body.error).toMatch(/Route '\/ping' Not Found\./);
expect(res.body.message).toMatch(/Route '\/ping' Not Found\./);
});
});
});
55 changes: 55 additions & 0 deletions api/__tests__/routes/profiles.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import request from 'supertest';
import express from 'express';
import * as Profiles from '../../models/profileModel';
import authRequired from '../../middleware/authRequired';
import profileRouter from '../../routes/profile';

const server = express();
jest.mock('../../models/profileModel');
jest.mock('../../middleware/authRequired',
() => jest.fn((req, res, next) => next()));

describe('profiles router endpoints', () => {
beforeAll(() => {
// This is the module/route being tested
server.use('/profiles', profileRouter);
});

describe('GET /profiles', () => {
it('should return 200', async () => {
Profiles.findAll.mockResolvedValue([]);
const res = await request(server).get('/profiles');

expect(res.status).toBe(200);
expect(res.body.length).toBe(0);
expect(Profiles.findAll.mock.calls.length).toBe(1);
});
});

describe('GET /profiles/:id', () => {
it('should return 200 when profile found', async () => {
Profiles.findById.mockResolvedValue({
id: 'd376de05-5f1b-4086-93b1-77681ca93614',
name: 'Bob Smith',
email: 'bob@example.com',
});
const res = await request(server).get(
'/profiles/d376de05-5f1b-4086-93b1-77681ca93614'
);

expect(res.status).toBe(200);
expect(res.body.name).toBe('Bob Smith');
expect(Profiles.findById.mock.calls.length).toBe(1);
});

it('should return 404 when no user found', async () => {
Profiles.findById.mockResolvedValue();
const res = await request(server).get(
'/profiles/d376de05-5f1b-4086-93b1-77681ca9361d'
);

expect(res.status).toBe(404);
expect(res.body.error).toBe('ProfileNotFound');
});
});
});
31 changes: 13 additions & 18 deletions api/app.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
var createError = require('http-errors');
var express = require('express');
const cors = require("cors");
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var helmet = require('helmet');
const dotenv = require('dotenv');
const config_result = dotenv.config();
if (config_result.error) {
throw config_result.error;
}
import createError from 'http-errors';
import express from 'express';
import cors from "cors";
import cookieParser from 'cookie-parser';
import logger from 'morgan';
import helmet from 'helmet';

var indexRouter = require('./routes/index');
var profileRouter = require('./routes/profile');
import indexRouter from './routes/index';
import profileRouter from './routes/profile';

var app = express();

app.use('/apidoc', express.static('apidoc'));
app.use('/apidoc', express.static('../apidoc'));
app.use(helmet());
app.use(
cors({
Expand All @@ -33,19 +28,19 @@ app.use(['/profile', '/profiles'], profileRouter);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
next(new createError.NotFound(`Route '${req.url}' Not Found.`));
});

// error handler
app.use(function (err, req, res, next) {
if (err instanceof createError.HttpError) {
if (createError.isHttpError(err)) {
res.locals.message = err.message;
res.locals.status = err.statusCode;
if (process.env.NODE_ENV === 'development') {
res.locals.error = err;
}
}
console.log(err);

if (process.env.NODE_ENV === 'production' && !res.locals.message) {
res.locals.message = 'ApplicationError';
res.locals.status = 500;
Expand All @@ -58,4 +53,4 @@ app.use(function (err, req, res, next) {
next(err);
});

module.exports = app;
export default app;
Loading