Creating a Backend with Ramses
Pizza is one of the most popular foods in the world. From traditional pepperoni to vegan options, there’s a pizza out there for everyone.
But have you ever wondered how the pizzeria manages to produce so many varieties? The answer is API.
At the core of a successful pizza factory is a well-designed backend system that manages the ingredients and the orders. An API or Application Programming Interface provides an interface for the front-end applications to communicate with the backend.
In this article, we shall explore how to create a backend using Ramses that can power your dream pizzeria.
Prerequisites
If you’re already familiar with development using Python, you might want to skip this part. However, it’s crucial to have a basic understanding of the tools we shall be using in this article.
1. Virtual environment:
A virtual environment is a self-contained Python environment that allows you to install dependencies for your project without affecting other projects outside the environment.
2. Elasticsearch:
This is a search engine built on top of Apache Lucene.
It’s a popular tool for data indexing and searching.
3. PostgreSQL:
This is a popular relational database that uses SQL.
It’s widely used for web applications.
4. Httpie:
This is a command-line HTTP client that allows you to send HTTP requests easily.
5. Curl:
This is a command-line tool that allows you to send HTTP requests.
6. HTTP clients:
We shall be using requests and urllib3 libraries for making HTTP requests using Python.
Scenario: A Factory to Make (Hopefully) Delicious Pizzas
Let’s imagine that you’re starting a pizzeria, and you need a system to manage the ingredients and orders. You want to create an API backend that can store the available toppings, cheeses, sauces, and crusts.
You also want the API to accept orders from customers and process them accordingly.
Data Modeling
The first step in creating a backend is to design the data model. The data model defines the structure of the data that the backend shall be handling.
In our case, we shall be using Ramses, which is a Python library for building REST APIs. To use Ramses, you need to define your data model using Python classes. To get started, we shall define four classes: Ingredient, Topping, Cheese, and Sauce.
Here’s an example of how to define the Ingredient class:
from ramses import fields, models
class Ingredient(models.Model):
name = fields.CharField(max_length=100)
price = fields.DecimalField()
The above code defines the Ingredient class with two properties: name and price. We’re using the fields module to define the datatype of each property.
CharField represents a character string, while DecimalField represents a decimal. We shall define the other classes similarly.
Relations 101
The next step is to define the relationships between the classes. In our case, we want to define a relationship between the pizza and its ingredients.
We shall use a foreign key to define the relationship. Here’s an example of how to define the relationship between the Pizza and Ingredient classes:
from ramses import fields, models
class Pizza(models.Model):
name = fields.CharField(max_length=100)
ingredients = fields.ManyToManyField('Ingredient')
class Ingredient(models.Model):
name = fields.CharField(max_length=100)
price = fields.DecimalField()
pizzas = fields.ManyToManyField('Pizza', related_name='ingredients')
The above code defines a many-to-many relationship between Pizza and Ingredient classes.
We define the relationship by using the ManyToManyField class. We also have to add the related_name parameter to the Pizza class to define the reverse relationship.
Creating Endpoints
Once we’ve defined our data model, we need to create API endpoints for the frontend to interact with. We shall use Flask-Restless, a Python library built on top of Flask and SQLAlchemy.
Flask-Restless provides an easy way to create REST APIs from SQLAlchemy models. To create an endpoint for our ingredients, we shall use the flask.ext.restless.create_api() function.
from flask import Flask
from flask.ext.restless import APIManager
from sqlalchemy import create_engine
from models import *
app = Flask(__name__)
engine = create_engine('postgresql://user:pass@localhost/db')
app.config['SQLALCHEMY_DATABASE_URI'] = engine.url
db.init_app(app)
with app.app_context():
db.create_all()
manager = APIManager(app, flask_sqlalchemy_db=db)
manager.create_api(Ingredient, methods=['GET', 'POST', 'DELETE', 'PUT'])
The above code creates an endpoint for our Ingredient class. We use the create_api() function to create the endpoint.
We define the allowed HTTP methods using the methods parameter.
Seed Data
Finally, we need to add some data to our backend. We shall use HTTPie to test our API.
We need to create a JSON file with our data. Here’s an example:
{
"objects": [
{
"name": "Pepperoni",
"price": "1.50"
},
{
"name": "Mushrooms",
"price": "0.75"
},
{
"name": "Onions",
"price": "0.35"
}
]
}
We can use the post2api command to send the data to our endpoint.
http POST localhost:5000/ingredient data.json
Conclusion
Creating a backend using Ramses is a powerful way to manage your data in a scalable and secure way. With Python, Flask-Restless, and Ramses, you can easily create an API that integrates with your front-end application.
In this article, we’ve covered the prerequisites, data modeling, defining relations, creating endpoints, and seeding data. Use this article as a starting point to create your next great web application.
3) Scenario: A Factory to Make (Hopefully) Delicious Pizzas
As discussed earlier, we shall be creating an API backend to manage our pizzeria’s ingredients and orders. In this section, we shall explore creating the Pizzeria API, installing the database backend, and running the built-in server.
Pizzeria API
The Pizzeria API endpoint is the main API endpoint for our pizzeria application. It shall be responsible for managing our toppings, cheeses, sauces, and crusts.
To create this endpoint, we shall use Flask-Restful, which is a Python library that allows us to create RESTful APIs.
Here’s an example of how to create the Pizzeria API endpoint using Flask-Restful:
from flask import Flask
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
class Toppings(Resource):
def get(self):
return {'toppings': ['Pepperoni', 'Mushrooms', 'Onions']}
api.add_resource(Toppings, '/toppings')
if __name__ == '__main__':
app.run(debug=True)
In the above code, we’ve defined the Toppings resource, which has a GET method that returns a list of toppings. We’ve also added the Toppings resource to the Pizzeria API using the add_resource() method.
Finally, we’ve used the run() function to start the Flask development server. We can now access our Pizzeria API using the following URL: http://localhost:5000/toppings.
Installer
To use SQLAlchemy with our application, we shall install it using pip. SQLAlchemy is a Python library that enables communication with databases.
We also need to install psycopg2, which is a PostgreSQL adapter for Python.
pip install SQLAlchemy psycopg2
After installing SQLAlchemy, we can create an instance of SQLAlchemy in our application and specify the database URI to use. Here’s an example:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:password@localhost/pizzeria'
db = SQLAlchemy(app)
if __name__ == '__main__':
app.run(debug=True)
In the above code, we’ve created a Flask application and specified the database URI to use. We’ve also created an instance of SQLAlchemy and assigned it to the db variable.
Running the Built-In Server
We can run the built-in server for our Pizzeria API using the following command:
python app.py
This starts a simple HTTP server on port 5000. We can then access our Pizzeria API using the following URL: http://localhost:5000/toppings.
RAML File
The RAML or RESTful API Modeling Language file is a YAML file that defines our endpoint’s base URI, mediaType, and protocols. We can create a RAML file as follows:
#%RAML 1.0
title: Pizzeria API
version: 1.0
baseUri: http://localhost:5000
mediaType: application/json
protocols: [HTTP, HTTPS]
/toppings:
get:
description: Returns a list of toppings
responses:
200:
body:
application/json:
example: [{"name": "Pepperoni", "price": 1.5},{"name": "Mushrooms", "price": 0.75}]
In the above RAML file, we’ve defined the base URI to be http://localhost:5000.
We’ve also defined the mediaType and protocols. We’ve defined the /toppings endpoint to have a GET method that returns a list of toppings in JSON format.
4) Data Modeling
In this section, we shall explore data modeling using schemas, editing schemas, and defining relations.
Schemas
A schema is a blueprint for data that defines the data structure. In Ramses, we define our schemas using Python classes or YAML files.
Here’s an example of how to define a schema using YAML:
Pizza:
type: object
properties:
name:
type: string
recipe:
type: object
properties:
instructions:
type: string
crust:
type: string
enum: [deep-dish, thin-crust]
topping:
type: array
items:
- type: string
cheese:
type: array
items:
- type: string
sauce:
type: array
items:
- type: string
The above YAML schema defines the Pizza schema with properties such as name, recipe, crust, topping, cheese, and sauce.
Editing Schemas
After defining a schema, we can edit it as follows:
Pizza:
type: object
properties:
name:
type: string
recipe:
type: object
properties:
instructions:
type: string
ingredients:
type: array
items:
type: string
style:
type: string
enum: [Neapolitan, Chicago-style, New York-style]
toppings:
type: array
items:
type: string
cheese:
type: array
items:
- type: string
sauce:
type: array
items:
- type: string
In the above example, we’ve added a new property to the Pizza schema called style.
We’ve also renamed the topping property to toppings and added an ingredients property to the recipe property.
Relations 101
In some cases, we need to define a relationship between our schema classes. For example, in our pizzeria, we need to define a relationship between the Pizza and Ingredient classes.
We shall use a foreign key to define the relationship. Here’s an example of how to define the relationship between the Pizza and Ingredient classes:
from ramses import fields, models
class Pizza(models.Model):
name = fields.CharField(max_length=100)
ingredient_id = fields.ForeignKeyField('Ingredient', related_name='pizzas')
class Ingredient(models.Model):
name = fields.CharField(max_length=100)
price = fields.FloatField()
The above code creates a one-to-many relationship between the Pizza and Ingredient classes.
We define the relationship using the ForeignKeyField class in the Pizza class. We also add the related_name parameter to the ingredient_id property to define the reverse relationship.
The ingredients property in the Ingredient class is not needed since we’re using a foreign key relationship.
5) Creating Endpoints
API endpoints provide a mechanism for the users of our API to interact with our data models.
In this section, we shall explore creating and editing endpoints using RAML and creating endpoints for two pizza styles, namely, Hawaiian-style and Vegetarian pizza.
General Overview
API endpoints are the entry points for the users of our API to access and manipulate our data models. A well-designed API should be easy to use and navigate.
To achieve this, we need to define our API endpoints in a clear and concise manner. To create endpoints, we need to define them in our RAML file.
RAML is a RESTful API modeling language that enables us to define our endpoints using YAML. We can create and edit our endpoints using a text editor such as Visual Studio Code.
Editing api.raml
To edit our RAML file, we need to open it in our text editor of choice. Once we’ve opened the file, we can start adding endpoints.
Here’s an example:
#%RAML 1.0
title: Pizzeria API
version: 1.0
baseUri: http://localhost:5000
mediaType: application/json
protocols: [HTTP, HTTPS]
/toppings:
get:
description: Returns a list of toppings
responses:
200:
body:
application/json:
example: [{"name": "Pepperoni", "price": 1.5},{"name": "Mushrooms", "price": 0.75}]
/pizzas:
get:
description: Returns a list of pizzas
responses:
200:
body:
application/json:
example: [{"name": "Margherita"}, {"name": "Pepperoni"}]
post:
description: Creates a new pizza
body:
application/json:
example: {"name": "Margherita"}
responses:
201:
body:
application/json:
example: {"id": 1, "name": "Margherita"}
/pizzas/{pizzaId}:
parameters:
- name: pizzaId
type: integer
description: The ID of the pizza to retrieve
required: true
example: 1
get:
description: Gets a single pizza
responses:
200:
body:
application/json:
example: {"id": 1, "name": "Margherita"}
In the above code, we’ve defined the /toppings and /pizzas endpoints. The /toppings endpoint has a GET method that returns a list of toppings.
The /pizzas endpoint has a GET and POST method that returns a list of pizzas and creates a new pizza, respectively. We’ve also defined a parameter {pizzaId} in the /pizzas/{pizzaId} endpoint to retrieve a single pizza.
Hawaiian Style Pizza
Hawaiian-style pizza is a popular pizza style that is characterized by its toppings of ham, pineapple, and cheese. To create an API endpoint for a Hawaiian-style pizza, we shall define the ingredients, toppings, and sauces.
Here’s an example of a Hawaiian-style pizza schema:
HawaiianPizza:
type: object
properties:
name:
type: string
crust:
type: string
enum: [deep-dish, thin-crust]
toppings:
type: array
items:
type: string
enum: [ham, pineapple]
cheese:
type: array
items:
type: string
enum: [mozzarella, g