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
78 changes: 4 additions & 74 deletions code/app.py
Original file line number Diff line number Diff line change
@@ -1,83 +1,13 @@
from flask import Flask
from flask_restful import Resource, Api, reqparse
from flask_restful import Api

from job import Job
from jobslist import JobsList

app = Flask(__name__)

api = Api(app)

jobs = []

class Job(Resource):
parser = reqparse.RequestParser()
parser.add_argument(
'company',
type=str,
required=True,
help="This field cannot be left blank"
)
parser.add_argument('salary')
parser.add_argument('status')

def post(self, title):

if self.check_for_job(title) is not None:
return{'message': "A job with name '{}' already exists".format(title)}, 400

data = Job.parser.parse_args()

job = {
'title': title,
'company': data['company'],
'salary': data['salary'],
'status': data['status']
}
jobs.append(job)

return job, 201

def check_for_job(self, title):
for job in jobs:
if job['title'] == title:
return job
return None

def get(self, title):
job = self.check_for_job(title)
if job:
return {'job': job}, 200
else:
return{"message": "Job does not exist"}, 404

def put(self, title):

data = Job.parser.parse_args()

job = self.check_for_job(title)
if job is None:
job = {
'title': title,
'company': data['company'],
'salary': data['salary'],
'status': data['status']
}
jobs.append(job), 201
else:
job.update(data), 200
return job

def delete(self, title):
if self.check_for_job(title) is None:
return{'message': "A job with name '{}' does not exist".format(title)}, 400
global jobs
jobs = list([job for job in jobs if job['title'] != title])
return {'message': 'Item deleted'}, 200


class JobsList(Resource):

def get(self):
return {"jobs": jobs}, 200

api.add_resource(Job, '/job/<string:title>')
api.add_resource(JobsList, '/jobs')

Expand Down
53 changes: 53 additions & 0 deletions code/job.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from flask_restful import Resource, reqparse

jobs = {}

class Job(Resource):
parser = reqparse.RequestParser()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a perfectly valid Python thing, but how come the parser is being set up as what would be called a static member in C#? i.e. rather than putting it in the init method and assigning it to self.parser.

The main reason I'm asking is that this class feels difficult to write unit tests for. I don't know how much of a thing this is in the Flask world, but you can use this package:

https://github.com/alecthomas/injector

to add the ability to inject dependencies in to url handlers. So, here you could have the parser injected in the constructor, which would then give you the ability to mock it in a unit test, and therefore be able to write unit tests much more easily.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To expand on this some more; I know that what you've got here is a very simple example ( no data store, for example), but I would be looking to split the data store (jobs) and the code that interacts with it, out in to a separate service class. This service class would then be injected in to this class. So this class would consist of the code to deal with getting the fields from the request, and the service class would deal with that data.

Does that make sense?

parser.add_argument(
'company',
type=str,
required=True,
help="This field cannot be left blank"
)
parser.add_argument('salary')
parser.add_argument('status')

def post(self, title):

if jobs.get(title):
return{'message': f"A job with name '{title}' already exists"}, 400

data = Job.parser.parse_args()

jobs.update(
{title : {
'company': data['company'],
'salary': data['salary'],
'status': data['status']
}
}
)
return jobs[title], 201

def get(self, title):
if jobs.get(title):
return jobs[title], 200
else:
return{"message": f"A job with neme {title} does not exist"}, 404

def put(self, title):

data = Job.parser.parse_args()

if jobs.get(title):
jobs[title].update(data), 200
return jobs[title]
else:
return self.post(title)

def delete(self, title):
if jobs.get(title) == None:
return {'message': f"A job with name '{title}' does not exist"}, 400
jobs.pop(title)
return {'message' : f"{title} deleted"}, 200
8 changes: 8 additions & 0 deletions code/jobslist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from flask_restful import Resource

import job

class JobsList(Resource):

def get(self):
return {"jobs": job.jobs}, 200