Skip to content
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

feature: completed test task #3

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.idea
node_modules/
dist

.npm
.env
.env.test

25 changes: 25 additions & 0 deletions README 2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# JS developer task

Your task is to create new endpoint.

When you are done, you can either send a pull request to this repository with your solution or email your solution to [HR manager](mailto:[email protected]).

You will then receive a detailed review of your code.

Good luck!

## Endpoint
### Country capital

Endpoint must return a capital of the provided country.

* Method: `GET`
* Endpoint: `http://localhost:3000/capital`
* Query parameters:
* `country`
* Example of request and what should be returned:
* `GET` `http://localhost:3000/capital?country=latvia`
* Returned text: `Capital of Latvia is Riga`
* Suggested modules to use:
* [country-json](https://github.com/samayo/country-json)
* [fs](https://nodejs.org/api/fs.html)
22 changes: 22 additions & 0 deletions app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import express from 'express';
import * as http from 'http';
import cors from 'cors';
import { CommonRoutesConfig } from './common/commonRoutesConfig';
import { CountriesRoutes } from './countries/countriesRoutesConfig';

const app: express.Application = express();
const server: http.Server = http.createServer(app);
const routes: Array<CommonRoutesConfig> = [];

app.use(express.json());
app.use(cors());

routes.push(new CountriesRoutes(app));

const runningMessage = `Server running at http://localhost:3000`;
app.get('/', (req: express.Request, res: express.Response) => {
res.status(200).send(runningMessage)
});
server.listen(3000, () => {
console.log(runningMessage);
});
10 changes: 10 additions & 0 deletions common/commonRoutesConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import express from 'express';
export abstract class CommonRoutesConfig {
app: express.Application;

constructor(app: express.Application) {
this.app = app;
this.configureRoutes();
}
abstract configureRoutes(): express.Application;
}
3 changes: 3 additions & 0 deletions common/interfaces/crudInterface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface CRUD {
getCapitalByCountry: (country: string) => Promise<any>;
}
25 changes: 25 additions & 0 deletions common/middleware/commonMiddleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import express from 'express';
import { validationResult } from 'express-validator';

class CommonMiddleware {
validate = (validations: any[]) => {
return async (
req: express.Request,
res: express.Response,
next: express.NextFunction
) => {
await Promise.all(validations.map(validation => validation.run(req)));

const errors = validationResult(req);
if (errors.isEmpty()) {
return next();
}

res.status(400).json({
errors: errors.array()
});
};
};
}

export default new CommonMiddleware();
18 changes: 18 additions & 0 deletions countries/controllers/countriesController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import express from 'express';
import countriesService from '../services/countriesService';

class CountriesController {
async getCapitalByCountry(req: express.Request, res: express.Response) {
const countryWithCapital = await countriesService.getCapitalByCountry(req.query.country as string);
let result = `Capital for ${req.query.country} Not Found`;
if (countryWithCapital) {
result = `Capital of ${countryWithCapital.country} is ${countryWithCapital.city}`;
}

res.status(200).json({
data: result
});
}
}

export default new CountriesController();
26 changes: 26 additions & 0 deletions countries/countriesRoutesConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { CommonRoutesConfig } from '../common/commonRoutesConfig';
import CountriesController from './controllers/countriesController';
import CommonMiddleware from '../common/middleware/commonMiddleware';
import express from 'express';
import { query } from 'express-validator';

export class CountriesRoutes extends CommonRoutesConfig {
constructor(app: express.Application) {
super(app);
}

configureRoutes() {
this.app
.route(`/capital`)
.get(
CommonMiddleware.validate([
query('country')
.notEmpty().withMessage('Is Required')
.isLength({ min: 3 }).withMessage('Min Length 3 symbols'),
]),
CountriesController.getCapitalByCountry
);

return this.app;
}
}
9 changes: 9 additions & 0 deletions countries/daos/countriesDao.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import countryByCapitalCity from 'country-json/src/country-by-capital-city.json';

class CountriesDao {
getCapitalByCountry(country: string) {
return countryByCapitalCity.find(item => item.country.toLowerCase() === country.toLowerCase());
}
}

export default new CountriesDao();
10 changes: 10 additions & 0 deletions countries/services/countriesService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import CountriesDao from '../daos/countriesDao';
import { CRUD } from '../../common/interfaces/crudInterface';

class CountriesService implements CRUD {
async getCapitalByCountry(country: string) {
return CountriesDao.getCapitalByCountry(country);
}
}

export default new CountriesService();
Loading