Как легко создать RESTful API с помощью Flask и APIFairy

В этом руководстве показано, как легко создать RESTful API с помощью Flask и APIFairy.

Цели

К концу этого урока вы сможете:

  1. Создавайте конечные точки API в Flask с помощью декораторов, предоставляемых APIFairy.
  2. Используйте Flask-Marshmallow для определения схем ввода/вывода для конечных точек API.
  3. Создайте документацию API с помощью APIFairy.
  4. Интеграция реляционной базы данных с конечными точками API
  5. Реализовать базовую и токеновую аутентификацию с помощью Flask-HTTPAuth.

Что такое APIFairy?

APIFairy — это платформа API, написанная Мигелем Гринбергом, которая позволяет легко создавать API с помощью Flask.

APIFairy предоставляет четыре ключевых компонента для простого создания API во Flask:

  1. Декораторы
  2. Схемы
  3. Аутентификация
  4. Документация

Давайте подробно рассмотрим каждый...

Декораторы

APIFairy предоставляет набор декораторов для определения входов, выходов и аутентификации для каждой конечной точки API:

APIFairy Decorators

APIFairy предоставляет пять основных декораторов:

  1. @arguments — указывает входные аргументы в строке запроса URL.
  2. @body — указывает входное тело JSON как схему
  3. @response — указывает тело вывода JSON в виде схемы
  4. @other_responses — указывает дополнительные ответы (часто ошибки), которые могут быть возвращены ( только документация )
  5. @authenticate — указывает процесс аутентификации

Схемы

Ввод (с помощью @bodyдекоратора) и вывод (с помощью @responseдекоратора) конечной точки API определяются как схемы:

class EntrySchema(ma.Schema):
    """Schema defining the attributes in a journal entry."""
    id = ma.Integer()
    entry = ma.String()
    user_id = ma.Integer()

Схемы используют зефир для определения типов данных как классов.

Аутентификация

Декоратор @authenticateиспользуется для проверки заголовка аутентификации, предоставленного в URL-запросе к каждой конечной точке API. Схема аутентификации реализована с помощью Flask-HTTPAuth , который также был создан Мигелем Гринбергом.

Типичным подходом к аутентификации API будет определение базовой аутентификации для защиты маршрута для получения токена аутентификации:

basic_auth = HTTPBasicAuth()

@basic_auth.verify_password
def verify_password(email, password):
    user = User.query.filter_by(email=email).first()
    if user.is_password_correct(password):
        return user

А также определить аутентификацию токена для защиты большинства маршрутов на основе чувствительного ко времени токена аутентификации:

token_auth = HTTPTokenAuth()

@token_auth.verify_token
def verify_token(auth_token):
    return User.verify_auth_token(auth_token)

Документация

Одной из замечательных особенностей APIFairy является красивая документация по API, которая генерируется автоматически:

Документация по API - главная страница

Документация создается на основе строк документации в исходном коде вместе со следующими переменными конфигурации:

  1. APIFAIRY_TITLE- название проекта
  2. APIFAIRY_VERSION- строка версии проекта
  3. APIFAIRY_UI- формат документации API

Для APIFAIRY_UI, вы можете создавать шаблоны из одного из следующих средств визуализации документации OpenAPI:

  1. Интерфейс Swagger
  2. Редок
  3. РапиДок
  4. Элементы

Полный список доступных переменных конфигурации см. в документации по конфигурации .

Что мы строим?

В этом руководстве вы будете разрабатывать API журнала, позволяющий пользователям вести ежедневный журнал событий. Вы можете найти полный исходный код в репозитории flask-journal-api на GitLab.

Основные используемые пакеты Python:

  1. Flask : микрофреймворк для разработки веб-приложений на Python.
  2. APIFairy : API-фреймворк для Flask, который использует:
    • Flask-Marshmallow : расширение Flask для использования зефира (библиотека сериализации/десериализации объектов)
    • Flask-HTTPAuth : расширение Flask для HTTP-аутентификации.
    • apispec — генератор спецификаций API, поддерживающий спецификацию OpenAPI .
  3. Flask-SQLAlchemy : ORM (реляционное сопоставление объектов) для Flask

Вы будете разрабатывать API постепенно:

  1. Создайте конечные точки API для работы с записями журнала.
  2. Создание документации по API
  3. Добавьте реляционную базу данных для хранения записей журнала.
  4. Добавьте аутентификацию для защиты конечных точек API.

Конечные точки API

Давайте перейдем к созданию API с помощью Flask и APIFairy...

Инициализация проекта

Start by creating a new project folder and a virtual environment:

$ mkdir flask-journal-api
$ cd flask-journal-api
$ python3 -m venv venv
$ source venv/bin/activate
(venv)$

Feel free to swap out virtualenv and Pip for Poetry or Pipenv. For more, review Modern Python Environments.

Go ahead and add the following files and folders:

├── app.py
├── instance
│   └── .gitkeep
├── project
│   ├── __init__.py
│   └── journal_api
│       ├── __init__.py
│       └── routes.py
└── requirements.txt

Next, to install the necessary Python packages, add the dependencies to the requirements.txt file in the project root:

apifairy==0.9.1
Flask==2.1.2
Flask-SQLAlchemy==2.5.1
marshmallow-sqlalchemy==0.28.0

Install:

(venv)$ pip install -r requirements.txt

This Flask project will utilize two best practices for Flask applications:

  1. Application Factory - used for creating the Flask application in a function
  2. Blueprints - used for organizing a group of related views

Application Factory

Start by defining the Application Factory function in project/__init__.py:

from apifairy import APIFairy
from flask import Flask, json
from flask_marshmallow import Marshmallow

# -------------
# Configuration
# -------------

# Create the instances of the Flask extensions in the global scope,
# but without any arguments passed in. These instances are not
# attached to the Flask application at this point.
apifairy = APIFairy()
ma = Marshmallow()


# ----------------------------
# Application Factory Function
# ----------------------------

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    initialize_extensions(app)
    register_blueprints(app)
    return app


# ----------------
# Helper Functions
# ----------------

def initialize_extensions(app):
    # Since the application instance is now created, pass it to each Flask
    # extension instance to bind it to the Flask application instance (app)
    apifairy.init_app(app)
    ma.init_app(app)


def register_blueprints(app):
    # Import the blueprints
    from project.journal_api import journal_api_blueprint

    # Since the application instance is now created, register each Blueprint
    # with the Flask application instance (app)
    app.register_blueprint(journal_api_blueprint, url_prefix='/journal')

После определения функции Application Factory ее можно вызвать в app.py в папке верхнего уровня проекта:

from project import create_app


# Call the application factory function to construct a Flask application
# instance using the development configuration
app = create_app()

План

Давайте определим journal_apiплан. Начните с определения схемы journal_apiв project/journal_api/__init__.py :

"""
The 'journal_api' blueprint handles the API for managing journal entries.
Specifically, this blueprint allows for journal entries to be added, edited,
and deleted.
"""
from flask import Blueprint

journal_api_blueprint = Blueprint('journal_api', __name__, template_folder='templates')

from . import routes

Теперь пришло время определить конечные точки API для журнала в project/journal_api/routes.py .

Начните с необходимого импорта:

from apifairy import body, other_responses, response
from flask import abort

from project import ma
from . import journal_api_blueprint

Для этой начальной версии Flask Journal API база данных будет представлять собой список записей журнала:

# --------
# Database
# --------

messages = [
    dict(id=1, entry='The sun was shining when I woke up this morning.'),
    dict(id=2, entry='I tried a new fruit mixture in my oatmeal for breakfast.'),
    dict(id=3, entry='Today I ate a great sandwich for lunch.')
]

Затем определите схемы для создания новой записи журнала и возврата записей журнала:

# -------
# Schemas
# -------

class NewEntrySchema(ma.Schema):
    """Schema defining the attributes when creating a new journal entry."""
    entry = ma.String(required=True)


class EntrySchema(ma.Schema):
    """Schema defining the attributes in a journal entry."""
    id = ma.Integer()
    entry = ma.String()


new_entry_schema = NewEntrySchema()
entry_schema = EntrySchema()
entries_schema = EntrySchema(many=True)

Оба этих класса схемы наследуются от ma.Schema , предоставляемого Flask-Marshmallow. Также рекомендуется создавать объекты этих схем, так как это позволяет определить схему, которая может возвращать несколько записей (используя many=Trueаргумент).

Теперь мы готовы определить конечные точки API!

Маршруты

Начните с извлечения всех записей журнала:

@journal_api_blueprint.route('/', methods=['GET'])
@response(entries_schema)
def journal():
    """Return all journal entries"""
    return messages

Эта функция представления использует @responseдекоратор, чтобы указать, что возвращаются несколько записей. Функция просмотра возвращает полный список записей журнала ( return messages).

Затем создайте конечную точку API для добавления новой записи журнала:

@journal_api_blueprint.route('/', methods=['POST'])
@body(new_entry_schema)
@response(entry_schema, 201)
def add_journal_entry(kwargs):
    """Add a new journal entry"""
    new_message = dict(**kwargs, id=messages[-1]['id']+1)
    messages.append(new_message)
    return new_message

Эта функция представления использует @bodyдекоратор для определения ввода в конечную точку API и @responseдекоратор для определения выходных данных из конечной точки API.

Входные данные, полученные от @bodyдекоратора, передаются в add_journal_entry()функцию представления в качестве аргумента ( kwargsаргументы ключевого слова ) . Затем эти данные используются для создания новой записи журнала и добавления ее в базу данных:

new_message = dict(**kwargs, id=messages[-1]['id']+1)
messages.append(new_message)

Затем возвращается вновь созданная запись журнала ( return new_message). Обратите внимание, как @responseдекоратор определяет код возврата как 201 (Создано), чтобы указать, что запись журнала была добавлена ​​в базу данных.

Создайте конечную точку API для получения определенной записи журнала:

@journal_api_blueprint.route('/<int:index>', methods=['GET'])
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def get_journal_entry(index):
    """Return a journal entry"""
    if index >= len(messages):
        abort(404)

    return messages[index]

Эта функция просмотра использует @other_responsesдекоратор для указания нестандартных ответов.

Декоратор @other_responsesиспользуется только для целей документации! Он не предоставляет никакой функциональности с точки зрения возврата кодов ошибок.

Create the API endpoint for updating a journal entry:

@journal_api_blueprint.route('/<int:index>', methods=['PUT'])
@body(new_entry_schema)
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def update_journal_entry(data, index):
    """Update a journal entry"""
    if index >= len(messages):
        abort(404)

    messages[index] = dict(data, id=index+1)
    return messages[index]

This view function uses the @body and @response decorators to define the inputs and outputs (respectively) for this API endpoint. Additionally, the @other_responses decorator defines the non-standard response if the journal entry is not found.

Finally, create the API endpoint for deleting a journal entry:

@journal_api_blueprint.route('/<int:index>', methods=['DELETE'])
@other_responses({404: 'Entry not found'})
def delete_journal_entry(index):
    """Delete a journal entry"""
    if index >= len(messages):
        abort(404)

    messages.pop(index)
    return '', 204

This view function does not use the @body and @response decorators, as there are no inputs or outputs for this API endpoint. If the journal entry is successfully deleted, then a 204 (No Content) status code is returned with no data.

Running the Flask Application

To test things out, within one terminal window, configure the Flask application and run the development server:

(venv) $ export FLASK_APP=app.py
(venv) $ export FLASK_ENV=development
(venv) $ flask run

Then, in a different terminal window, you can interact with the API. Feel free to use your tool of choice here, like cURL, HTTPie, Requests, or Postman.

Requests example:

$ python3

>>> import requests
>>>
>>> r = requests.get('http://127.0.0.1:5000/journal/')
>>> print(r.text)
>>>
>>> post_data = {'entry': "some message"}
>>> r = requests.post('http://127.0.0.1:5000/journal/', json=post_data)
>>> print(r.text)

Want to test out the API endpoints more easily? Check out this script, which adds CLI commands for interacting with the API endpoints for retrieving, creating, updating, and deleting journal entries.

Documentation

An incredible feature of APIFairy is the automatic API documentation creation!

There are three key aspects to configuring the API documentation:

  1. Docstrings for the API endpoints (i.e., view functions)
  2. Docstring for the overall API project
  3. Configuration variables to specify the look of the API documentation

Мы уже рассмотрели первый пункт в предыдущем разделе, так как включили строки документации для каждой функции представления. Например, journal()функция просмотра имеет краткое описание назначения этой конечной точки API:

@journal_api_blueprint.route('/', methods=['GET'])
@response(entries_schema)
def journal():
    """Return all journal entries"""
    return messages

Затем нам нужно включить строку документации для описания всего проекта в самом верху файла project/__init__.py :

"""
Welcome to the documentation for the Flask Journal API!

## Introduction

The Flask Journal API is an API (Application Programming Interface) for creating a **daily journal** that documents events that happen each day.

## Key Functionality

The Flask Journal API has the following functionality:

1. Work with journal entries:
  * Create a new journal entry
  * Update a journal entry
  * Delete a journal entry
  * View all journal entries
2. <More to come!>

## Key Modules

This project is written using Python 3.10.1.

The project utilizes the following modules:

* **Flask**: micro-framework for web application development which includes the following dependencies:
  * **click**: package for creating command-line interfaces (CLI)
  * **itsdangerous**: cryptographically sign data
  * **Jinja2**: templating engine
  * **MarkupSafe**: escapes characters so text is safe to use in HTML and XML
  * **Werkzeug**: set of utilities for creating a Python application that can talk to a WSGI server
* **APIFairy**: API framework for Flask which includes the following dependencies:
  * **Flask-Marshmallow** - Flask extension for using Marshmallow (object serialization/deserialization library)
  * **Flask-HTTPAuth** - Flask extension for HTTP authentication
  * **apispec** - API specification generator that supports the OpenAPI specification
* **pytest**: framework for testing Python projects
"""
...

Эта строка документации используется для описания всего проекта, включая ключевые функции и ключевые пакеты Python, используемые в проекте.

Наконец, необходимо определить некоторые переменные конфигурации, чтобы указать внешний вид документации API. Обновите create_app()функцию в project/__init__.py :

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    # Configure the API documentation
    app.config['APIFAIRY_TITLE'] = 'Flask Journal API'
    app.config['APIFAIRY_VERSION'] = '0.1'
    app.config['APIFAIRY_UI'] = 'elements'

    initialize_extensions(app)
    register_blueprints(app)

    return app

Готовы ознакомиться с документацией по проекту? Запустите сервер разработки Flask через flask run, а затем перейдите по адресу http://127.0.0.1:5000/docs , чтобы просмотреть документацию по API, созданную APIFairy:

Документация по API - главная страница

На левой панели есть список конечных точек API для journal_apiсхемы. При нажатии на одну из конечных точек отображаются все сведения об этой конечной точке:

Документация по API — получить конечную точку API для записи журнала

Что удивительно в этой документации API, так это возможность увидеть, как работают конечные точки API (при условии, что сервер разработки Flask работает). На правой панели документации введите индекс записи журнала и нажмите «Отправить запрос API». Затем отображается ответ API:

Документация по API - Получить ответ API записи журнала

Эта интерактивная документация облегчает пользователям понимание API!

База данных

For demonstration purposes, a SQLite database will be used in this tutorial.

Configuration

Since Flask-SQLAlchemy was already installed at the beginning of this tutorial, we need to configure it in the project/__init__.py file.

Start by creating a SQLAlchemy() object in the 'Configuration' section:

...

from apifairy import APIFairy
from flask import Flask, json
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy  # <-- NEW!!


# -------------
# Configuration
# -------------

# Create the instances of the Flask extensions in the global scope,
# but without any arguments passed in. These instances are not
# attached to the Flask application at this point.
apifairy = APIFairy()
ma = Marshmallow()
database = SQLAlchemy()  # <-- NEW!!

...

Next, update the create_app() function to specify the necessary configuration variables:

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    # Configure the API documentation
    app.config['APIFAIRY_TITLE'] = 'Flask Journal API'
    app.config['APIFAIRY_VERSION'] = '0.1'
    app.config['APIFAIRY_UI'] = 'elements'

    # NEW!
    # Configure the SQLite database (intended for development only!)
    app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{os.path.join(os.getcwd(), 'instance', 'app.db')}"
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    initialize_extensions(app)
    register_blueprints(app)

    return app

Add the import to the top:

import os

The SQLALCHEMY_DATABASE_URI configuration variable is critical to identifying the location of the SQLite database. For this tutorial, the database is stored in instance/app.db.

Finally, update the initialize_extensions() function to initialize the Flask-SQLAlchemy object:

def initialize_extensions(app):
    # Since the application instance is now created, pass it to each Flask
    # extension instance to bind it to the Flask application instance (app)
    apifairy.init_app(app)
    ma.init_app(app)
    database.init_app(app)  # <-- NEW!!

Want to learn more about how this Flask app is wired together? Check out my course on how to build, test, and deploy a Flask application:

Database Model

Create a new project/models.py file to define the database table to represent the journal entries:

from project import database


class Entry(database.Model):
    """Class that represents a journal entry."""
    __tablename__ = 'entries'

    id = database.Column(database.Integer, primary_key=True)
    entry = database.Column(database.String, nullable=False)

    def __init__(self, entry: str):
        self.entry = entry

    def update(self, entry: str):
        self.entry = entry

    def __repr__(self):
        return f'<Entry: {self.entry}>'

This new class, Entry, specifies that the entries database table will contain two elements (for now!) to represent a journal entry:

  1. id - the primary key (primary_key=True) for the table, which means that it's a unique identifier for each element (row) in the table
  2. entry - string for storing the journal entry text

While models.py defines the database table, it doesn't create the tables in the SQLite database. To create the tables, start the Flask shell in a terminal window:

(venv)$ flask shell

>>> from project import database
>>> database.drop_all()
>>> database.create_all()
>>> quit()

(venv)$

Journal API Updates

Since we're progressing on to use a SQLite database, start by deleting the temporary database (Python list) that was defined in project/journal_api/routes.py:

# --------
# Database
# --------

messages = [
    dict(id=1, entry='The sun was shining when I woke up this morning.'),
    dict(id=2, entry='I tried a new fruit mixture in my oatmeal for breakfast.'),
    dict(id=3, entry='Today I ate a great sandwich for lunch.')
]

Next, we need to update each API endpoint (i.e., the view functions) to utilize the SQLite database.

Start by updating the journal() view function:

@journal_api_blueprint.route('/', methods=['GET'])
@response(entries_schema)
def journal():
    """Return all journal entries"""
    return Entry.query.all()

The complete list of journal entries is now retrieved from the SQLite database. Notice how the schemas or decorators for this view function did not need to change... only the underlying process for getting the users changed!

Add the import:

from project.models import Entry

Next, update the add_journal_entry() view function:

@journal_api_blueprint.route('/', methods=['POST'])
@body(new_entry_schema)
@response(entry_schema, 201)
def add_journal_entry(kwargs):
    """Add a new journal entry"""
    new_message = Entry(**kwargs)
    database.session.add(new_message)
    database.session.commit()
    return new_message

The inputs to this view function are specified by new_entry_schema:

class NewEntrySchema(ma.Schema):
    """Schema defining the attributes when creating a new journal entry."""
    entry = ma.String(required=True)

new_entry_schema = NewEntrySchema()

The entry string is used to create a new instance of the Entry class (defined in models.py) and this journal entry is then added to the database.

Add the import:

from project import database

Next, update get_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['GET'])
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def get_journal_entry(index):
    """Return a journal entry"""
    entry = Entry.query.filter_by(id=index).first_or_404()
    return entry

This function now attempts to look up the specified journal entry (based on the index):

entry = Entry.query.filter_by(id=index).first_or_404()

If the entry exists, it's returned to the user. If the entry does not exist, a 404 (Not Found) error is returned.

Next, update update_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['PUT'])
@body(new_entry_schema)
@response(entry_schema)
@other_responses({404: 'Entry not found'})
def update_journal_entry(data, index):
    """Update a journal entry"""
    entry = Entry.query.filter_by(id=index).first_or_404()
    entry.update(data['entry'])
    database.session.add(entry)
    database.session.commit()
    return entry

The update_journal_entry() view function now attempts to retrieve the specified journal entry:

entry = Entry.query.filter_by(id=index).first_or_404()

If the journal entry exists, the entry is updated with the new text and then saved to the database.

Finally, update delete_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['DELETE'])
@other_responses({404: 'Entry not found'})
def delete_journal_entry(index):
    """Delete a journal entry"""
    entry = Entry.query.filter_by(id=index).first_or_404()
    database.session.delete(entry)
    database.session.commit()
    return '', 204

If the specified journal entry is found, then it's deleted from the database.

Run the development server. Test out each of the endpoints to ensure they still work.

Error Handling

Since this Flask project is an API, error codes should be returned in JSON format instead of the typical HTML format.

In the Flask project, this can be accomplished by using a custom error handler. In project/__init__.py, define a new function (register_error_handlers()) at the bottom of the file:

def register_error_handlers(app):
    @app.errorhandler(HTTPException)
    def handle_http_exception(e):
        """Return JSON instead of HTML for HTTP errors."""
        # Start with the correct headers and status code from the error
        response = e.get_response()
        # Replace the body with JSON
        response.data = json.dumps({
            'code': e.code,
            'name': e.name,
            'description': e.description,
        })
        response.content_type = 'application/json'
        return response

This function registers a new error handler for when an HTTPException is raised to convert the output into JSON format.

Add the import:

from werkzeug.exceptions import HTTPException

Also, update the Application Factory function, create_app(), to call this new function:

def create_app():
    # Create the Flask application
    app = Flask(__name__)

    # Configure the API documentation
    app.config['APIFAIRY_TITLE'] = 'Flask Journal API'
    app.config['APIFAIRY_VERSION'] = '0.1'
    app.config['APIFAIRY_UI'] = 'elements'

    # Configure the SQLite database (intended for development only!)
    app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{os.path.join(os.getcwd(), 'instance', 'app.db')}"
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    initialize_extensions(app)
    register_blueprints(app)
    register_error_handlers(app)  # NEW!!

    return app

Authentication

Authentication is the process of validating the identity of a user attempting to access a system, which in this case is the API.

Authorization, on the other hand, is the process of verifying what specific resources a specific user should have access to.

APIFairy utilizes Flask-HTTPAuth for authentication support. In this tutorial, we'll be using Flask-HTTPAuth in two manners:

  1. Basic Authentication - used to generate a token based on the user's email/password
  2. Token Authentication - used to authenticate the user on all other API endpoints

Аутентификация токена , используемая через Flask-HTTPAuth, часто называется аутентификацией носителя, поскольку процесс вызывает предоставление доступа к «носителю» токена. Маркер должен быть включен в заголовки HTTP в заголовке авторизации, например «Авторизация: носитель».

На следующей диаграмме показан типичный процесс взаимодействия нового пользователя с приложением для получения маркера аутентификации.

Блок-схема API журнала Flask

Конфигурация

Поскольку Flask-HTTPAuth уже был установлен при установке APIFairy в начале этого руководства, нам просто нужно настроить его в файле project/__init__.py .

Начните с создания отдельных объектов для базовой и токеновой аутентификации:

...

import os

from apifairy import APIFairy
from flask import Flask, json
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth  # NEW!!
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
from werkzeug.exceptions import HTTPException


# -------------
# Configuration
# -------------

# Create the instances of the Flask extensions in the global scope,
# but without any arguments passed in. These instances are not
# attached to the Flask application at this point.
apifairy = APIFairy()
ma = Marshmallow()
database = SQLAlchemy()
basic_auth = HTTPBasicAuth()  # NEW!!
token_auth = HTTPTokenAuth()  # NEW!!

...

Никаких дальнейших обновлений в project/__init__.py не требуется .

Модель базы данных

В project/models.py необходимо создать новую Userмодель для представления пользователя:

class User(database.Model):
    __tablename__ = 'users'

    id = database.Column(database.Integer, primary_key=True)
    email = database.Column(database.String, unique=True, nullable=False)
    password_hashed = database.Column(database.String(128), nullable=False)
    entries = database.relationship('Entry', backref='user', lazy='dynamic')
    auth_token = database.Column(database.String(64), index=True)
    auth_token_expiration = database.Column(database.DateTime)

    def __init__(self, email: str, password_plaintext: str):
        """Create a new User object."""
        self.email = email
        self.password_hashed = self._generate_password_hash(password_plaintext)

    def is_password_correct(self, password_plaintext: str):
        return check_password_hash(self.password_hashed, password_plaintext)

    def set_password(self, password_plaintext: str):
        self.password_hashed = self._generate_password_hash(password_plaintext)

    @staticmethod
    def _generate_password_hash(password_plaintext):
        return generate_password_hash(password_plaintext)

    def generate_auth_token(self):
        self.auth_token = secrets.token_urlsafe()
        self.auth_token_expiration = datetime.utcnow() + timedelta(minutes=60)
        return self.auth_token

    @staticmethod
    def verify_auth_token(auth_token):
        user = User.query.filter_by(auth_token=auth_token).first()
        if user and user.auth_token_expiration > datetime.utcnow():
            return user

    def revoke_auth_token(self):
        self.auth_token_expiration = datetime.utcnow()

    def __repr__(self):
        return f'<User: {self.email}>'

Добавьте импорт:

import secrets
from datetime import datetime, timedelta

from werkzeug.security import check_password_hash, generate_password_hash

Модель Userиспользует werkzeug.securityдля хэширования пароль пользователя перед его сохранением в базе данных.

Помните: никогда не храните открытый пароль в базе данных!

Модель Userиспользует secretsдля создания токена аутентификации для конкретного пользователя. Этот токен создается в generate_auth_token()методе и включает дату/время истечения срока действия 60 минут в будущем:

def generate_auth_token(self):
    self.auth_token = secrets.token_urlsafe()
    self.auth_token_expiration = datetime.utcnow() + timedelta(minutes=60)
    return self.auth_token

Существует статический метод, verify_auth_token()который используется для проверки токена аутентификации (с учетом времени истечения срока действия) и возврата пользователя из действительного токена:

@staticmethod
def verify_auth_token(auth_token):
    user = User.query.filter_by(auth_token=auth_token).first()
    if user and user.auth_token_expiration > datetime.utcnow():
        return user

Еще один интересный метод — revoke_auth_token(), который используется для отзыва токена аутентификации для конкретного пользователя:

def revoke_auth_token(self):
    self.auth_token_expiration = datetime.utcnow()

Начальная модель

Чтобы установить отношение «один ко многим» между пользователем («один») и его записями («многие»), Entryнеобходимо обновить модель, чтобы связать таблицы entriesи вместе:users

class Entry(database.Model):
    """Class that represents a journal entry."""
    __tablename__ = 'entries'

    id = database.Column(database.Integer, primary_key=True)
    entry = database.Column(database.String, nullable=False)
    user_id = database.Column(database.Integer, database.ForeignKey('users.id'))  # <-- NEW!!

    def __init__(self, entry: str):
        self.entry = entry

    def update(self, entry: str):
        self.entry = entry

    def __repr__(self):
        return f'<Entry: {self.entry}>'

Модель Userуже содержит обратную ссылку на entriesтаблицу:

entries = database.relationship('Entry', backref='user', lazy='dynamic')

Схема пользовательского API

Функциональность управления пользователями проекта Flask будет определена в отдельном проекте Blueprint под названием users_api_blueprint.

Начните с создания нового каталога в «проекте» с именем «users_api». В этом каталоге создайте файл __init__.py :

from flask import Blueprint


users_api_blueprint = Blueprint('users_api', __name__)

from . import authentication, routes

Этот новый Blueprint необходимо зарегистрировать в Flask appв файле Projects/__init__.py внутри register_blueprints()функции:

def register_blueprints(app):
    # Import the blueprints
    from project.journal_api import journal_api_blueprint
    from project.users_api import users_api_blueprint  # NEW!!

    # Since the application instance is now created, register each Blueprint
    # with the Flask application instance (app)
    app.register_blueprint(journal_api_blueprint, url_prefix='/journal')
    app.register_blueprint(users_api_blueprint, url_prefix='/users')  # NEW!!

Функции аутентификации

Чтобы использовать Flask-HTTPAuth, необходимо определить несколько функций для проверки учетных данных пользователя.

Создайте новый файл project/users_api/authentication.py для обработки базовой проверки подлинности и проверки подлинности токена.

Для базовой аутентификации (проверка электронной почты и пароля пользователя):

from werkzeug.exceptions import Forbidden, Unauthorized

from project import basic_auth, token_auth
from project.models import User


@basic_auth.verify_password
def verify_password(email, password):
    user = User.query.filter_by(email=email).first()
    if user is None:
        return None

    if user.is_password_correct(password):
        return user


@basic_auth.error_handler
def basic_auth_error(status=401):
    error = (Forbidden if status == 403 else Unauthorized)()
    return {
        'code': error.code,
        'message': error.name,
        'description': error.description,
    }, error.code, {'WWW-Authenticate': 'Form'}

Функция verify_password()используется для проверки существования пользователя и правильности его пароля. Эта функция будет использоваться Flask-HTTPAuth для проверки пароля, когда требуется базовая аутентификация (спасибо @basic_auth.verify_passwordдекоратору).

Кроме того, для базовой проверки подлинности определен обработчик ошибок, который возвращает информацию об ошибке в формате JSON.

Для аутентификации токена (обработка токена, чтобы определить, действителен ли пользователь):

@token_auth.verify_token
def verify_token(auth_token):
    return User.verify_auth_token(auth_token)


@token_auth.error_handler
def token_auth_error(status=401):
    error = (Forbidden if status == 403 else Unauthorized)()
    return {
        'code': error.code,
        'message': error.name,
        'description': error.description,
    }, error.code

Функция verify_token()используется для проверки правильности токена аутентификации. Эта функция будет использоваться Flask-HTTPAuth для проверки токена, когда требуется аутентификация токена (спасибо @token_auth.verify_tokenдекоратору).

Кроме того, для проверки подлинности токена определен обработчик ошибок, который возвращает информацию об ошибке в формате JSON.

Маршруты пользователей

В users_api_blueprint, будет два маршрута:

  1. Регистрация нового пользователя
  2. Получение токена аутентификации

Для начала необходимо определить новый набор схем (с использованием зефира) в файле project/users_api/routes.py :

from project import ma

from . import users_api_blueprint

# -------
# Schemas
# -------

class NewUserSchema(ma.Schema):
    """Schema defining the attributes when creating a new user."""
    email = ma.String()
    password_plaintext = ma.String()


class UserSchema(ma.Schema):
    """Schema defining the attributes of a user."""
    id = ma.Integer()
    email = ma.String()


class TokenSchema(ma.Schema):
    """Schema defining the attributes of a token."""
    token = ma.String()


new_user_schema = NewUserSchema()
user_schema = UserSchema()
token_schema = TokenSchema()

Эти схемы будут использоваться для определения входных и выходных данных для функций просмотра, определенных в этом файле.

Регистрация нового пользователя

Затем определите функцию представления для регистрации нового пользователя:

@users_api_blueprint.route('/', methods=['POST'])
@body(new_user_schema)
@response(user_schema, 201)
def register(kwargs):
    """Create a new user"""
    new_user = User(**kwargs)
    database.session.add(new_user)
    database.session.commit()
    return new_user

Добавьте импорт:

from apifairy import authenticate, body, other_responses, response

from project import basic_auth, database, ma
from project.models import User

Эта конечная точка API использует , new_user_schemaчтобы указать, что адрес электронной почты и пароль являются входными данными.

ПРИМЕЧАНИЕ. Поскольку электронная почта и пароль отправляются на эту конечную точку API, самое время вспомнить, что использование HTTP допустимо во время тестирования разработки, но HTTPS (безопасный) всегда следует использовать в рабочей среде.

Электронная почта и пароль (определенные как kwargsаргументы ключевого слова) затем распаковываются для создания нового Userобъекта, который сохраняется в базе данных:

new_user = User(**kwargs)
database.session.add(new_user)
database.session.commit()

Выходные данные конечной точки API определяются user_schemaидентификатором и адресом электронной почты нового пользователя.

Получение токена аутентификации

Другая функция представления, которую необходимо определить в файле project/users_api/routes.py , предназначена для получения токена аутентификации:

@users_api_blueprint.route('/get-auth-token', methods=['POST'])
@authenticate(basic_auth)
@response(token_schema)
@other_responses({401: 'Invalid username or password'})
def get_auth_token():
    """Get authentication token"""
    user = basic_auth.current_user()
    token = user.generate_auth_token()
    database.session.add(user)
    database.session.commit()
    return dict(token=token)

Декоратор @authenticateиспользуется в этом руководстве впервые и указывает, что для защиты этого маршрута следует использовать базовую аутентификацию:

@authenticate(basic_auth)

Когда пользователь хочет получить свой токен аутентификации, ему необходимо отправить запрос POST на эту конечную точку API с адресом электронной почты и паролем, встроенными в заголовок «Авторизация». Например, следующая команда Python с использованием пакета Requests может быть выполнена для этой конечной точки API:

>>> import requests
>>> r = requests.post(
    'http://127.0.0.1:5000/users/get-auth-token',
    auth=('pkennedy@hey.com', 'FlaskIsAwesome123')
)

Если базовая аутентификация прошла успешно, функция просмотра извлекает текущего пользователя, используя current_user()метод, предоставляемый Flask-HTTPAuth:

user = basic_auth.current_user()

Для этого пользователя создается новый токен аутентификации:

token = user.generate_auth_token()

И этот токен сохраняется в базе данных, чтобы его можно было использовать для аутентификации пользователя в будущем (по крайней мере, в течение следующих 60 минут!).

Наконец, новый токен аутентификации возвращается пользователю для сохранения для всех последующих вызовов API.

Обновления конечной точки API

При наличии процесса аутентификации пришло время добавить некоторые средства защиты к существующим конечным точкам API, чтобы убедиться, что только действительные пользователи могут получить доступ к приложению.

Эти обновления предназначены для функций представления, определенных в файле Projects/journal_api/routes.py .

Во- первых, обновите, journal()чтобы возвращались только записи журнала для текущего пользователя:

@journal_api_blueprint.route('/', methods=['GET'])
@authenticate(token_auth)
@response(entries_schema)
def journal():
    """Return journal entries"""
    user = token_auth.current_user()
    return Entry.query.filter_by(user_id=user.id).all()

Обновите импорт вверху следующим образом:

from apifairy import authenticate, body, other_responses, response
from flask import abort

from project import database, ma, token_auth
from project.models import Entry

from . import journal_api_blueprint

@authenticateДекоратор указывает, что при доступе к этой конечной точке API необходимо использовать аутентификацию с помощью токена . В качестве примера можно сделать следующий запрос GET с использованием запросов ( после получения токена аутентификации ):

>>> import requests
>>> headers = {'Authorization': f'Bearer {auth_token}'}
>>> r = requests.get('http://127.0.0.1:5000/journal/', headers=headers)

После аутентификации пользователя полный список записей журнала извлекается из базы данных на основе идентификатора пользователя:

user = token_auth.current_user()
return Entry.query.filter_by(user_id=user.id).all()

Выходные данные этой конечной точки API определяются @responseдекоратором, который представляет собой список записей журнала (идентификатор, запись, идентификатор пользователя).

Далее обновите add_journal_entry():

@journal_api_blueprint.route('/', methods=['POST'])
@authenticate(token_auth)
@body(new_entry_schema)
@response(entry_schema, 201)
def add_journal_entry(kwargs):
    """Add a new journal entry"""
    user = token_auth.current_user()
    new_message = Entry(user_id=user.id, **kwargs)
    database.session.add(new_message)
    database.session.commit()
    return new_message

Как и в предыдущей функции представления, @authenticateдекоратор используется для указания того, что при доступе к этой конечной точке API необходимо использовать аутентификацию с помощью токена. Кроме того, запись журнала теперь добавляется путем указания идентификатора пользователя, который должен быть связан с записью журнала:

user = token_auth.current_user()
new_message = Entry(user_id=user.id, **kwargs)

Новая запись журнала сохраняется в базе данных, и запись журнала возвращается (как определено @responseдекоратором).

Далее обновите get_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['GET'])
@authenticate(token_auth)
@response(entry_schema)
@other_responses({403: 'Forbidden', 404: 'Entry not found'})
def get_journal_entry(index):
    """Return a journal entry"""
    user = token_auth.current_user()
    entry = Entry.query.filter_by(id=index).first_or_404()

    if entry.user_id != user.id:
        abort(403)
    return entry

Добавляется @authenticateдекоратор, чтобы указать, что для доступа к этой конечной точке API необходима проверка подлинности токена.

При попытке получить запись журнала добавляется дополнительная проверка, чтобы убедиться, что пользователь, пытающийся получить доступ к записи журнала, является фактическим «владельцем» записи. Если нет, то через abort()функцию из Flask возвращается код ошибки 403 (Forbidden):

if entry.user_id != user.id:
        abort(403)

Обратите внимание, что эта конечная точка API имеет два нестандартных ответа, указанных @other_responsesдекоратором:

@other_responses({403: 'Forbidden', 404: 'Entry not found'})

Напоминание: @other_responsesдекоратор предназначен только для документации; функция просмотра несет ответственность за возникновение этих ошибок.

Далее обновите update_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['PUT'])
@authenticate(token_auth)
@body(new_entry_schema)
@response(entry_schema)
@other_responses({403: 'Forbidden', 404: 'Entry not found'})
def update_journal_entry(data, index):
    """Update a journal entry"""
    user = token_auth.current_user()
    entry = Entry.query.filter_by(id=index).first_or_404()

    if entry.user_id != user.id:
        abort(403)

    entry.update(data['entry'])
    database.session.add(entry)
    database.session.commit()
    return entry

Обновления этой функции просмотра аналогичны другим функциям просмотра в этом разделе:

  1. @authenticateдекоратор указывает, что для доступа к этой конечной точке API необходима аутентификация токена.
  2. Только пользователь, который «владеет» записью журнала, может обновлять запись (в противном случае 403 (Запрещено))

Наконец, обновите delete_journal_entry():

@journal_api_blueprint.route('/<int:index>', methods=['DELETE'])
@authenticate(token_auth)
@other_responses({403: 'Forbidden', 404: 'Entry not found'})
def delete_journal_entry(index):
    """Delete a journal entry"""
    user = token_auth.current_user()
    entry = Entry.query.filter_by(id=index).first_or_404()

    if entry.user_id != user.id:
        abort(403)

    database.session.delete(entry)
    database.session.commit()
    return '', 204

Вывод

В этом руководстве показано, как легко и быстро создать API во Flask с помощью APIFairy.

Декораторы — это ключ к определению конечных точек API:

  • Входы :
    • @arguments- входные аргументы из строки запроса URL
    • @body- структура JSON-запроса
  • Выходы :
    • @response- структура ответа JSON
  • Аутентификация :
    • @authenticate- подход к аутентификации с использованием Flask-HTTPAuth
  • Ошибки :
    • @other_responses- нестандартные ответы, такие как коды ошибок HTTP

Кроме того, документация API, созданная APIFairy, превосходна и предоставляет ключевую информацию для пользователей приложения.

Источник:  https://testdriven.io

#api #flask 

What is GEEK

Buddha Community

Как легко создать RESTful API с помощью Flask и APIFairy
Wilford  Pagac

Wilford Pagac

1594289280

What is REST API? An Overview | Liquid Web

What is REST?

The REST acronym is defined as a “REpresentational State Transfer” and is designed to take advantage of existing HTTP protocols when used for Web APIs. It is very flexible in that it is not tied to resources or methods and has the ability to handle different calls and data formats. Because REST API is not constrained to an XML format like SOAP, it can return multiple other formats depending on what is needed. If a service adheres to this style, it is considered a “RESTful” application. REST allows components to access and manage functions within another application.

REST was initially defined in a dissertation by Roy Fielding’s twenty years ago. He proposed these standards as an alternative to SOAP (The Simple Object Access Protocol is a simple standard for accessing objects and exchanging structured messages within a distributed computing environment). REST (or RESTful) defines the general rules used to regulate the interactions between web apps utilizing the HTTP protocol for CRUD (create, retrieve, update, delete) operations.

What is an API?

An API (or Application Programming Interface) provides a method of interaction between two systems.

What is a RESTful API?

A RESTful API (or application program interface) uses HTTP requests to GET, PUT, POST, and DELETE data following the REST standards. This allows two pieces of software to communicate with each other. In essence, REST API is a set of remote calls using standard methods to return data in a specific format.

The systems that interact in this manner can be very different. Each app may use a unique programming language, operating system, database, etc. So, how do we create a system that can easily communicate and understand other apps?? This is where the Rest API is used as an interaction system.

When using a RESTful API, we should determine in advance what resources we want to expose to the outside world. Typically, the RESTful API service is implemented, keeping the following ideas in mind:

  • Format: There should be no restrictions on the data exchange format
  • Implementation: REST is based entirely on HTTP
  • Service Definition: Because REST is very flexible, API can be modified to ensure the application understands the request/response format.
  • The RESTful API focuses on resources and how efficiently you perform operations with it using HTTP.

The features of the REST API design style state:

  • Each entity must have a unique identifier.
  • Standard methods should be used to read and modify data.
  • It should provide support for different types of resources.
  • The interactions should be stateless.

For REST to fit this model, we must adhere to the following rules:

  • Client-Server Architecture: The interface is separate from the server-side data repository. This affords flexibility and the development of components independently of each other.
  • Detachment: The client connections are not stored on the server between requests.
  • Cacheability: It must be explicitly stated whether the client can store responses.
  • Multi-level: The API should work whether it interacts directly with a server or through an additional layer, like a load balancer.

#tutorials #api #application #application programming interface #crud #http #json #programming #protocols #representational state transfer #rest #rest api #rest api graphql #rest api json #rest api xml #restful #soap #xml #yaml

An API-First Approach For Designing Restful APIs | Hacker Noon

I’ve been working with Restful APIs for some time now and one thing that I love to do is to talk about APIs.

So, today I will show you how to build an API using the API-First approach and Design First with OpenAPI Specification.

First thing first, if you don’t know what’s an API-First approach means, it would be nice you stop reading this and check the blog post that I wrote to the Farfetchs blog where I explain everything that you need to know to start an API using API-First.

Preparing the ground

Before you get your hands dirty, let’s prepare the ground and understand the use case that will be developed.

Tools

If you desire to reproduce the examples that will be shown here, you will need some of those items below.

  • NodeJS
  • OpenAPI Specification
  • Text Editor (I’ll use VSCode)
  • Command Line

Use Case

To keep easy to understand, let’s use the Todo List App, it is a very common concept beyond the software development community.

#api #rest-api #openai #api-first-development #api-design #apis #restful-apis #restful-api

Lets Cms

Lets Cms

1652251528

Opencart REST API extensions - V3.x | Rest API Integration, Affiliate

Opencart REST API extensions - V3.x | Rest API Integration : OpenCart APIs is fully integrated with the OpenCart REST API. This is interact with your OpenCart site by sending and receiving data as JSON (JavaScript Object Notation) objects. Using the OpenCart REST API you can register the customers and purchasing the products and it provides data access to the content of OpenCart users like which is publicly accessible via the REST API. This APIs also provide the E-commerce Mobile Apps.

Opencart REST API 
OCRESTAPI Module allows the customer purchasing product from the website it just like E-commerce APIs its also available mobile version APIs.

Opencart Rest APIs List 
Customer Registration GET APIs.
Customer Registration POST APIs.
Customer Login GET APIs.
Customer Login POST APIs.
Checkout Confirm GET APIs.
Checkout Confirm POST APIs.


If you want to know Opencart REST API Any information, you can contact us at -
Skype: jks0586,
Email: letscmsdev@gmail.com,
Website: www.letscms.com, www.mlmtrees.com
Call/WhatsApp/WeChat: +91–9717478599.

Download : https://www.opencart.com/index.php?route=marketplace/extension/info&extension_id=43174&filter_search=ocrest%20api
View Documentation : https://www.letscms.com/documents/api/opencart-rest-api.html
More Information : https://www.letscms.com/blog/Rest-API-Opencart
VEDIO : https://vimeo.com/682154292  

#opencart_api_for_android #Opencart_rest_admin_api #opencart_rest_api #Rest_API_Integration #oc_rest_api #rest_api_ecommerce #rest_api_mobile #rest_api_opencart #rest_api_github #rest_api_documentation #opencart_rest_admin_api #rest_api_for_opencart_mobile_app #opencart_shopping_cart_rest_api #opencart_json_api

Lets Cms

Lets Cms

1652251629

Unilevel MLM Wordpress Rest API FrontEnd | UMW Rest API Woocommerce

Unilevel MLM Wordpress Rest API FrontEnd | UMW Rest API Woocommerce Price USA, Philippines : Our API’s handle the Unilevel MLM woo-commerce end user all functionalities like customer login/register. You can request any type of information which is listed below, our API will provide you managed results for your all frontend needs, which will be useful for your applications like Mobile App etc.
Business to Customer REST API for Unilevel MLM Woo-Commerce will empower your Woo-commerce site with the most powerful Unilevel MLM Woo-Commerce REST API, you will be able to get and send data to your marketplace from other mobile apps or websites using HTTP Rest API request.
Our plugin is used JWT authentication for the authorization process.

REST API Unilevel MLM Woo-commerce plugin contains following APIs.
User Login Rest API
User Register Rest API
User Join Rest API
Get User info Rest API
Get Affiliate URL Rest API 
Get Downlines list Rest API
Get Bank Details Rest API
Save Bank Details Rest API
Get Genealogy JSON Rest API
Get Total Earning Rest API
Get Current Balance Rest API
Get Payout Details Rest API
Get Payout List Rest API
Get Commissions List Rest API
Withdrawal Request Rest API
Get Withdrawal List Rest API

If you want to know more information and any queries regarding Unilevel MLM Rest API Woocommerce WordPress Plugin, you can contact our experts through 
Skype: jks0586, 
Mail: letscmsdev@gmail.com,
Website: www.letscms.com, www.mlmtrees.com,
Call/WhatsApp/WeChat: +91-9717478599.  

more information : https://www.mlmtrees.com/product/unilevel-mlm-woocommerce-rest-api-addon

Visit Documentation : https://letscms.com/documents/umw_apis/umw-apis-addon-documentation.html

#Unilevel_MLM_WooCommerce_Rest_API's_Addon #umw_mlm_rest_api #rest_api_woocommerce_unilevel #rest_api_in_woocommerce #rest_api_woocommerce #rest_api_woocommerce_documentation #rest_api_woocommerce_php #api_rest_de_woocommerce #woocommerce_rest_api_in_android #woocommerce_rest_api_in_wordpress #Rest_API_Woocommerce_unilevel_mlm #wp_rest_api_woocommerce

Adonis  Kerluke

Adonis Kerluke

1596509565

RESTful API Design Driven Approach

In this tutorial I will show you the fundamentals of designing a RESTful API specification by applying REST principles and best practices, then you’ll be ready to try my online tutorial: How to design a REST API with API Designer?

If you already know what is meant by API in the context of RESTful web services, you can skip to the next section. If not, read on.

Level-Set on API

The abbreviation API stands for Application Programming Interface this in itself, does not help us understand what it is, however in the context of web services, it can refer to one of two things:

  1. The RESTful API specification is written using a modeling language such as Open API specification or RAML (RESTful API Modeling Language) that defines a contract for how software components can interact with a service.
  2. The implementation of a web service or microservice whose contract is designed by REST principles that describe how other services must interact with it.

In this post, I will use the first understanding of this term. Even though both are correct, the most technically relevant for this post is the first: an API is a contract for how software applications talk to each other.

Level-Set on REST

The acronym REST stands for REpresentational State Transfer. It is an architectural style used to represent the transmission of data from one application component to another. In the context of web services, we are talking about the representation of resources (i.e. data) transferred over HTTP by calling a URI that represents the data and via an HTTP method that represents the action to perform against the given data.

What Is RESTful API design?

RESTful API design is the activity of describing the behavior of a web service in terms of its data structures and the actions you allow other application components to perform on its data by the principles of REST. Those principles are covered later in this blog.

Why Design a RESTful API?

Imagine that you are an Architect (the kind the design building) and you set out to build an office block without a blueprint. You turn up on the first day with a truck full of bricks and some cement. What are the chances that you’ll be successful and build a structure that conforms to code and more importantly, doesn’t fall? It’s about zero. Without a blueprint the chance of failure is high.

The same approach applies to web service development. You need a blueprint, or more appropriately, an API specification. This is necessary to evaluate the API design and solicit feedback before even starting to build the implementation.

In addition to providing a specification for the web service’s development, an API contract serves to document its expected behavior, data types, and security requirements.

You should now be satisfied that API design is necessary for a RESTful web service, and should start to wonder how is the best approach to actually designing an API specification.

API Design Tooling

The tooling chosen by an API designer has substantial influence over the designer’s productivity. Highly productive tools such as the Anypoint API Designer from MuleSoft is perfect for designing APIs with OAS (swagger) or RAML.

#integration #api #rest #rest api #restful #api design #raml #rest api design