RESTFUL API
Published: 2024-05-22 19:30:11

In the fast moving, ever evolving world of web development, optimization is the rule of the land. People want a seamless experience on the web and are all to quick to move on if they are getting the experience they want. Using a RESTFUL API with Flask is a way developers can bring that client experience to meet these expectations while not losing anything on the server side. The combination of improved performance with scalability is the perfect solution to modern day web development.

Using RESTful API is a secure, reliable, and efficient way to transfer information across the internet. Some key principles include: Uniform interface, statelessness, layered system, cache ability, and code on demand. What this means is clients can access and use the resource (the information) they need to complete their task with minimal interruption while still connecting to other authorized intermediaries.

If we wanted to create an app to track baseball players using Flask and a RESTful API we could start by using SQLAlchemy to initiate a database. 

```
class Player(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    position = db.Column(db.String(100), nullable=False)
    team = db.Column(db.String(100), nullable=False)
    stats = db.relationship('Stat', backref='player')
```

We now have a database that will store players, assigning them an ID, name, position, team and stats. But we want each player to display their stats. So we set up a stat class as well with the following.

```
class Stat(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    player_id = db.Column(db.Integer, db.ForeignKey('player.id'), nullable=False)
    games_played = db.Column(db.Integer)
    hits = db.Column(db.Integer)
    home_runs = db.Column(db.Integer)
```

We can now check for each player how many games they have played and how many hits and homeruns they have. This is a great start but now we want to be able to communicate this information to the client so they can use and manipulate it. For that we need to set up some endpoints.

First we want to be able to get all the players from the db.

```
@app.route('/players', methods=['GET'])
def get_players():
    players = Player.query.all()
    return jsonify([{'id': player.id, 'name': player.name, 'position': player.position, 'team': player.team} for player in players])
```

Then we might want to look at a specific player. To do that we use the ID we assigned in models, while also adding some error validation.

```
@app.route('/players/<int:player_id>', methods=['GET'])
def get_player(player_id):
    player = Player.query.get(player_id)
    if player:
        stats = [{'id': stat.id, 'games_played': stat.games_played, 'hits': stat.hits, 'home_runs': stat.home_runs} for stat in player.stats]
        return jsonify({'id': player.id, 'name': player.name, 'position': player.position, 'team': player.team, 'stats': stats})
    else:
        return jsonify({"error": "Player not found"}), 404
```
While searching for players is useful, what if the client wanted to be able to actually update the data. To do that we need a post request.

```
@app.route('/players', methods=['POST'])
def create_player():
    data = request.json
    player = Player(name=data['name'], position=data['position'], team=data['team'])
    db.session.add(player)
    db.session.commit()
    return jsonify({'id': player.id, 'name': player.name, 'position': player.position, 'team': player.team}), 201
```
Great! We created a new player. But how can we update their stats? Say hello to the put request.

```
@app.route('/players/<int:player_id>', methods=['PUT'])
def update_player(player_id):
    player = Player.query.get(player_id)
    if player:
        data = request.json
        player.name = data.get('name', player.name)
        player.position = data.get('position', player.position)
        player.team = data.get('team', player.team)
        db.session.commit()
        return jsonify({'id': player.id, 'name': player.name, 'position': player.position, 'team': player.team})
    else:
        return jsonify({"error": "Player not found"}), 404
```
With this, now you can update any player in the db to reflect their stats. 

So far we are able to get all players, search for a specific player, add a player and update a player; so no surprise the last bit of code we need is delete player.

```
@app.route('/players/<int:player_id>', methods=['DELETE'])
def delete_player(player_id):
    player = Player.query.get(player_id)
    if player:
        db.session.delete(player)
        db.session.commit()
        return '', 204
    else:
        return jsonify({"error": "Player not found"}), 404
```
We now have a very barebones code structure that can track a baseball player and their stats while using RESTful API, SQLAlchemy and Flask. This is a good starting to point to continue to build from.