3
\$\begingroup\$

I have written REST API for random number generation using Falcon(https://falconframework.org/), just for my learning process.

This is API:

http "localhost:8000/random-number?min=10&max=10"

This is code:

class RandomNumber:
    def on_get(self, req, resp):
        """Handles GET requests"""

        if 'min' not in req.params:
            raise falcon.HTTPMissingParam('min')

        if 'max' not in req.params:
            raise falcon.HTTPMissingParam('max')

        min_n = req.params['min']
        max_n = req.params['max']

        if min_n.isnumeric() == False:
            raise falcon.HTTPInvalidParam('min must be number', min_n)

        if max_n.isnumeric() == False:
            raise falcon.HTTPInvalidParam('max must be number', max_n)

        min_n =int(min_n)
        max_n =int(max_n)

        if min_n > max_n:
            raise falcon.HTTPInvalidParam('min is bigger than max', (min_n, max_n))

        number = random.randint(min_n, max_n)
        result = {'lowerLimit': min_n, 'higherLimit': max_n, 'number': number}
        resp.media = result

api = falcon.API()
api.add_route('/random-number', RandomNumber())

Feedback appreciated.

\$\endgroup\$
2
\$\begingroup\$

I don't have many great suggestions, but I'll offer a few minor thoughts. If someone else comes along with a better answer, they're free to incorporate these:

  • Spaces after equals signs:

    min_n = int(min_n)  # <-- not "=int..."
    
  • You have some code duplication in parsing an integer HTTP argument. This could be encapsulated like so:

    def numeric_param(req, name):
        try:
            return int(req.params[name])
        except KeyError:
            raise falcon.HTTPMissingParam(name)
        except ValueError:
            raise falcon.HTTPInvalidParam('{} must be an integer'.format(name), val)
    
    class RandomNumber:
        def on_get(self, req, resp):
            """Handles GET requests"""
    
            min_n = numeric_param(req, 'min')
            max_n = numeric_param(req, 'max')
    

    Note too that I've taken the slightly more standard (in Python) approach of "try and fail gracefully" rather than explicitly checking if I think I'll be able to succeed; e.g., I just index params and catch a KeyError if it's not there, and I convert the result to an int and catch a ValueError if it's not possible.

  • I've more often seen "upper limit" as opposed to "higher limit".

Again, these are just minor suggestions, I really don't know how the code could be substantially better to accomplish the same task.

\$\endgroup\$
2
\$\begingroup\$

This is a small code, but there are some improvements to make:

  1. useless copy-paste, what if you had 5 conditions?:

    if 'min' not in req.params:
        raise falcon.HTTPMissingParam('min')
    
    if 'max' not in req.params:
        raise falcon.HTTPMissingParam('max')
    

when you can do:

for c in ['min','max']:
  if c not in req.params:
      raise falcon.HTTPMissingParam(c)
  1. don't test with == False

    if min_n.isnumeric() ==  False:
    

should be

    if not min_n.isnumeric():
\$\endgroup\$
  • \$\begingroup\$ I do not know why, but for me, it is much easier to see/understand min_n.isnumeric() == False than not min_n.isnumeric(). That is why I am still using X == False instead of not X. \$\endgroup\$ – WebOrCode May 3 '18 at 14:07
  • \$\begingroup\$ it's because it's bad to do == True. Read stackoverflow.com/a/4050625/6451573 \$\endgroup\$ – Jean-François Fabre May 3 '18 at 14:18
1
\$\begingroup\$

Because the answers before me were great, I would just like to put a little emphasis on EAFP and duck typing concepts.

When new (and veteran) developers are exposed to Python, they usually bring the influence they have experienced from other languages.

And that's why they miss all the power of language, And the truth is that it almost always happens when you switch languages.

As they have already said in the previous answers, Python has a lot of power and convenience to deal with errors in a dynamic way. You do not have to check everything five times before trying it, as they say "If it walks like a duck and then it has to be a duck." (Duck typing concept). Any way with this concept the code look more clear and even pretty.

In your case this is just a small example of the subject of power of language. No matter what language you're programming, always check that you're using the power of language for your own good.

In python case, try to find the pythonic way to do something, as the Zen of Python says:

"There should be one-- and preferably only one --obvious way to do it."

Sharing a link about Duck typing/EAFP: https://youtu.be/x3v9zMX1s4s

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.