Como Criar Facilmente Uma API RESTful Com Flask E APIFairy

Este tutorial demonstra como criar facilmente uma API RESTful com Flask e APIFairy.

Objetivos

Ao final deste tutorial, você será capaz de:

  1. Crie endpoints de API no Flask usando os decoradores fornecidos pela APIFairy
  2. Utilize Flask-Marshmallow para definir os esquemas de entradas/saídas para os endpoints da API
  3. Gere a documentação da API usando APIFairy
  4. Integrar um banco de dados relacional com os endpoints da API
  5. Implemente autenticação básica e de token usando Flask-HTTPAuth

O que é APIFairy?

APIFairy é um framework de API escrito por Miguel Grinberg que permite criar facilmente uma API com Flask.

APIFairy fornece quatro componentes principais para criar facilmente uma API no Flask:

  1. Decoradores
  2. Esquemas
  3. Autenticação
  4. Documentação

Vamos explorar cada um em detalhes...

Decoradores

APIFairy fornece um conjunto de decoradores para definir as entradas, saídas e autenticação para cada endpoint da API:

APIFairy Decorators

APIFairy fornece cinco decoradores principais:

  1. @arguments - especifica os argumentos de entrada na string de consulta da URL
  2. @body - especifica o corpo JSON de entrada como um esquema
  3. @response - especifica o corpo JSON de saída como um esquema
  4. @other_responses - especifica respostas adicionais (geralmente erros) que podem ser retornadas ( apenas documentação )
  5. @authenticate - especifica o processo de autenticação

Esquemas

A entrada (usando o @bodydecorador) e a saída (usando o @responsedecorador) de um endpoint de API são definidas como esquemas:

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

Os esquemas utilizam marshmallow para definir os tipos de dados como classes.

Autenticação

O @authenticatedecorador é usado para verificar o cabeçalho de autenticação fornecido na solicitação de URL para cada endpoint da API. O esquema de autenticação é implementado usando Flask-HTTPAuth , que também foi criado por Miguel Grinberg.

Uma abordagem típica de autenticação de API seria definir a autenticação básica para proteger a rota para recuperar um token de autenticação:

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

E também para definir a autenticação de token para proteger a maioria das rotas com base em um token de autenticação sensível ao tempo:

token_auth = HTTPTokenAuth()

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

Documentação

Um dos grandes recursos do APIFairy é a bela documentação da API que é gerada automaticamente:

Documentação da API - Página principal

A documentação é gerada com base em docstrings no código-fonte junto com as seguintes variáveis ​​de configuração:

  1. APIFAIRY_TITLE- nome do projeto
  2. APIFAIRY_VERSION- string de versão do projeto
  3. APIFAIRY_UI- formato da documentação da API

Para APIFAIRY_UI, você pode gerar modelos de um dos seguintes renderizadores de documentação OpenAPI:

  1. IU do Swagger
  2. ReDoc
  3. RapiDoc
  4. Elementos

Para obter uma lista completa de variáveis ​​de configuração disponíveis, consulte os documentos de configuração .

O que estamos construindo?

Você desenvolverá uma API de diário neste tutorial, permitindo que os usuários mantenham um diário de eventos. Você pode encontrar o código-fonte completo no repositório flask-journal-api no GitLab.

Principais pacotes Python usados:

  1. Flask : micro-framework para desenvolvimento de aplicações web em Python
  2. APIFairy : framework de API para Flask, que usa-
  3. Flask-SQLAlchemy : ORM (Object Relational Mapper) para Flask

Você desenvolverá a API de forma incremental:

  1. Crie os endpoints da API para trabalhar com entradas de diário
  2. Gerar documentação da API
  3. Adicionar um banco de dados relacional para armazenar as entradas de diário
  4. Adicionar autenticação para proteger os endpoints da API

Pontos de extremidade da API

Vamos pular para a criação de uma API usando Flask e APIFairy...

Inicialização do projeto

Comece criando uma nova pasta de projeto e um ambiente virtual:

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

Sinta-se à vontade para trocar virtualenv e Pip por Poetry ou Pipenv . Para saber mais, revise Ambientes Python Modernos .

Vá em frente e adicione os seguintes arquivos e pastas:

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

Em seguida, para instalar os pacotes Python necessários, adicione as dependências ao arquivo requirements.txt na raiz do projeto:

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

Instalar:

(venv)$ pip install -r requirements.txt

Este projeto Flask utilizará duas práticas recomendadas para aplicativos Flask:

  1. Application Factory - usado para criar o aplicativo Flask em uma função
  2. Blueprints - usados ​​para organizar um grupo de visualizações relacionadas

Fábrica de aplicativos

Comece definindo a função Application Factory em 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')

Com a função Application Factory definida, ela pode ser chamada em app.py na pasta de nível superior do projeto:

from project import create_app


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

Planta

Vamos definir o journal_apiplano. Comece definindo o journal_apiblueprint em 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

Agora é hora de definir os endpoints da API para o diário em project/journal_api/routes.py .

Comece com as importações necessárias:

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

from project import ma
from . import journal_api_blueprint

Para esta versão inicial da API do Flask Journal, o banco de dados será uma lista de entradas de diário:

# --------
# 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.')
]

Em seguida, defina os esquemas para criar uma nova entrada de diário e para retornar as entradas de diário:

# -------
# 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)

Ambas as classes de esquema herdam de ma.Schema , que é fornecido pelo Flask-Marshmallow. Também é uma boa ideia criar objetos desses esquemas, pois isso permite definir um esquema que pode retornar várias entradas (usando o many=Trueargumento).

Agora estamos prontos para definir os endpoints da API!

Rotas

Comece recuperando todas as entradas de diário:

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

Essa função de exibição usa o @responsedecorador para definir que várias entradas sejam retornadas. A função de visualização retorna a lista completa de entradas de diário ( return messages).

Em seguida, crie o endpoint da API para adicionar uma nova entrada de diário:

@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

Essa função de visualização usa o @bodydecorador para definir a entrada para o endpoint da API e o @responsedecorador para definir a saída do endpoint da API.

Os dados de entrada que são analisados ​​do @bodydecorador são passados ​​para a função add_journal_entry()de visualização como o argumento kwargs( argumentos da palavra - chave ). Esses dados são então usados ​​para criar uma nova entrada de diário e adicioná-la ao banco de dados:

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

A entrada de diário recém-criada é então retornada ( return new_message). Observe como o @responsedecorador define o código de retorno como 201 (Criado) para indicar que a entrada de diário foi adicionada ao banco de dados.

Crie o endpoint da API para recuperar uma entrada de diário específica:

@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]

Esta função de visualização usa o @other_responsesdecorador para especificar respostas não padrão.

O @other_responsesdecorador é usado apenas para fins de documentação! Ele não fornece nenhuma funcionalidade em termos de retorno de códigos de erro.

Crie o endpoint da API para atualizar uma entrada de diário:

@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]

Essa função de visualização usa os decoradores @bodye @responsepara definir as entradas e saídas (respectivamente) para este endpoint da API. Além disso, o @other_responsesdecorador define a resposta não padrão se a entrada de diário não for encontrada.

Por fim, crie o endpoint da API para excluir uma entrada de diário:

@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

Esta função de visualização não usa os decoradores @bodye @response, pois não há entradas ou saídas para este endpoint da API. Se a entrada de diário for excluída com sucesso, um código de status 204 (Sem conteúdo) será retornado sem dados.

Executando o aplicativo Flask

Para testar as coisas, em uma janela de terminal, configure o aplicativo Flask e execute o servidor de desenvolvimento:

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

Então, em uma janela de terminal diferente, você pode interagir com a API. Sinta-se à vontade para usar sua ferramenta de escolha aqui, como cURL, HTTPie , Requests ou Postman .

Exemplo de solicitações:

$ 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)

Quer testar os endpoints da API com mais facilidade? Confira este script , que adiciona comandos da CLI para interagir com os endpoints da API para recuperar, criar, atualizar e excluir entradas de diário.

Documentação

Um recurso incrível do APIFairy é a criação automática de documentação da API!

Há três aspectos principais para configurar a documentação da API:

  1. Docstrings para os endpoints da API (ou seja, funções de visualização)
  2. Docstring para o projeto geral da API
  3. Variáveis ​​de configuração para especificar a aparência da documentação da API

Já abordamos o primeiro item na seção anterior, pois incluímos as docstrings para cada função de visualização. Por exemplo, a journal()função de visualização tem uma breve descrição da finalidade deste endpoint da API:

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

Em seguida, precisamos incluir a docstring para descrever o projeto geral no topo do arquivo 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
"""
...

Esta docstring é usada para descrever o projeto geral, incluindo a funcionalidade chave fornecida e os principais pacotes Python usados ​​pelo projeto.

Por fim, algumas variáveis ​​de configuração precisam ser definidas para especificar a aparência da documentação da API. Atualize a create_app()função em 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

Pronto para ver a documentação do projeto? Inicie o servidor de desenvolvimento Flask via flask rune navegue até http://127.0.0.1:5000/docs para ver a documentação da API criada pela APIFairy:

Documentação da API - Página principal

No painel esquerdo, há uma lista de endpoints de API para o journal_apiblueprint. Clicar em um dos endpoints mostra todos os detalhes sobre esse endpoint:

Documentação da API - Obter ponto final da API de entrada de diário

O que é incrível nessa documentação da API é a capacidade de ver como os endpoints da API funcionam (supondo que o servidor de desenvolvimento do Flask esteja em execução). No painel direito da documentação, insira um índice de lançamento contábil manual e clique em "Enviar solicitação de API". A resposta da API é então exibida:

Documentação da API - Obter resposta da API de lançamento no diário

Esta documentação interativa torna mais fácil para os usuários entenderem a API!

Base de dados

Para fins de demonstração, um banco de dados SQLite será usado neste tutorial.

Configuração

Como o Flask-SQLAlchemy já estava instalado no início deste tutorial, precisamos configurá-lo no arquivo project/__init__.py .

Comece criando um SQLAlchemy()objeto na seção 'Configuração':

...

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!!

...

Em seguida, atualize a create_app()função para especificar as variáveis ​​de configuração necessárias:

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

Adicione a importação ao topo:

import os

A SQLALCHEMY_DATABASE_URIvariável de configuração é fundamental para identificar a localização do banco de dados SQLite. Para este tutorial, o banco de dados é armazenado em instance/app.db .

Por fim, atualize a initialize_extensions()função para inicializar o objeto Flask-SQLAlchemy:

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!!

Quer saber mais sobre como este aplicativo Flask está conectado? Confira meu curso sobre como construir, testar e implantar um aplicativo Flask:

Modelo de banco de dados

Crie um novo arquivo project/models.py para definir a tabela de banco de dados para representar as entradas de diário:

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}>'

Essa nova classe, Entry, especifica que a entriestabela do banco de dados conterá dois elementos (por enquanto!) para representar uma entrada de diário:

  1. id- a chave primária ( primary_key=True) para a tabela, o que significa que é um identificador exclusivo para cada elemento (linha) na tabela
  2. entry- string para armazenar o texto do lançamento contábil manual

Embora o models.py defina a tabela do banco de dados, ele não cria as tabelas no banco de dados SQLite. Para criar as tabelas, inicie o shell Flask em uma janela de terminal:

(venv)$ flask shell

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

(venv)$

Atualizações da API de diário

Como estamos progredindo para usar um banco de dados SQLite, comece excluindo o temporário database(lista Python) que foi definido em 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.')
]

Em seguida, precisamos atualizar cada endpoint da API (ou seja, as funções de visualização) para utilizar o banco de dados SQLite.

Comece atualizando a journal()função de visualização:

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

A lista completa de entradas de diário agora é recuperada do banco de dados SQLite. Observe como os esquemas ou decoradores para esta função de visualização não precisaram ser alterados... apenas o processo subjacente para alterar os usuários!

Adicione a importação:

from project.models import Entry

Em seguida, atualize a add_journal_entry()função de visualização:

@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

As entradas para esta função de visualização são especificadas por 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()

A entrystring é usada para criar uma nova instância da Entryclasse (definida em models.py ) e esta entrada de diário é então adicionada ao banco de dados.

Adicione a importação:

from project import database

A seguir, atualize 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

Esta função agora tenta pesquisar a entrada de diário especificada (com base no index):

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

Se a entrada existir, ela será devolvida ao usuário. Se a entrada não existir, um erro 404 (Não encontrado) será retornado.

A seguir, atualize 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

A update_journal_entry()função de visualização agora tenta recuperar a entrada de diário especificada:

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

Se a entrada de diário existir, a entrada é atualizada com o novo texto e salva no banco de dados.

Por fim, atualize 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

Se a entrada de diário especificada for encontrada, ela será excluída do banco de dados.

Execute o servidor de desenvolvimento. Teste cada um dos endpoints para garantir que eles ainda funcionem.

Manipulação de erros

Como este projeto Flask é uma API, os códigos de erro devem ser retornados no formato JSON em vez do formato HTML típico.

No projeto Flask, isso pode ser feito usando um manipulador de erros personalizado. Em project/__init__.py , defina uma nova função ( register_error_handlers()) na parte inferior do arquivo:

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

Essa função registra um novo manipulador de erros para quando um HTTPExceptioné gerado para converter a saída no formato JSON.

Adicione a importação:

from werkzeug.exceptions import HTTPException

Além disso, atualize a função Application Factory, create_app(), para chamar essa nova função:

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

Autenticação

Autenticação é o processo de validação da identidade de um usuário que tenta acessar um sistema, que neste caso é a API.

A autorização, por outro lado, é o processo de verificar a quais recursos específicos um usuário específico deve ter acesso.

APIFairy utiliza Flask-HTTPAuth para suporte de autenticação. Neste tutorial, usaremos o Flask-HTTPAuth de duas maneiras:

  1. Autenticação básica - usada para gerar um token com base no e-mail/senha do usuário
  2. Autenticação de token - usada para autenticar o usuário em todos os outros endpoints da API

A autenticação de token usada via Flask-HTTPAuth é frequentemente chamada de autenticação de portador, pois o processo invoca a concessão de acesso ao "portador" do token. O token deve ser incluído nos cabeçalhos HTTP no cabeçalho Authorization, como "Authorization: Bearer ".

O diagrama a seguir ilustra um fluxo típico de como um novo usuário interage com o aplicativo para recuperar um token de autenticação:

Diagrama de fluxo da API do Flask Journal

Configuração

Como o Flask-HTTPAuth já estava instalado quando o APIFairy foi instalado no início deste tutorial, precisamos apenas configurá-lo no arquivo project/__init__.py .

Comece criando objetos separados para a autenticação básica e de token:

...

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!!

...

Nenhuma atualização adicional é necessária em project/__init__.py .

Modelo de banco de dados

Em project/models.py , um novo Usermodelo precisa ser criado para representar um usuário:

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}>'

Adicione as importações:

import secrets
from datetime import datetime, timedelta

from werkzeug.security import check_password_hash, generate_password_hash

O Usermodelo usa werkzeug.securitypara fazer o hash da senha do usuário antes de armazená-la no banco de dados.

Lembre-se: Nunca armazene a senha de texto simples em um banco de dados!

O Usermodelo usa secretspara gerar um token de autenticação para um usuário específico. Este token é criado no generate_auth_token()método e inclui uma data/hora de expiração de 60 minutos no futuro:

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

Existe um método estático, verify_auth_token(), que é usado para verificar o token de autenticação (considerando o tempo de expiração) e retornar o usuário de um token válido:

@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

Mais um método de interesse é revoke_auth_token(), que é usado para revogar o token de autenticação para um usuário específico:

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

Modelo de entrada

Para estabelecer o relacionamento um para muitos entre o usuário ("um") e suas entradas ("muitos"), o Entrymodelo precisa ser atualizado para vincular as tabelas e 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}>'

O Usermodelo já contém o link de volta para a entriestabela:

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

Modelo de API de usuários

A funcionalidade de gerenciamento de usuários do projeto Flask será definida em um Blueprint separado chamado users_api_blueprint.

Comece criando um novo diretório em "project" chamado "users_api". Dentro desse diretório, crie um arquivo __init__.py :

from flask import Blueprint


users_api_blueprint = Blueprint('users_api', __name__)

from . import authentication, routes

Este novo Blueprint precisa ser registrado com o Flask appem projects/__init__.py dentro da register_blueprints()função:

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!!

Funções de autenticação

Para usar o Flask-HTTPAuth, várias funções precisam ser definidas para lidar com a verificação das credenciais do usuário.

Crie um novo arquivo project/users_api/authentication.py para lidar com a autenticação básica e a autenticação de token.

Para a autenticação básica (verificar o e-mail e a senha de um usuário):

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'}

A verify_password()função é usada para verificar se um usuário existe e se sua senha está correta. Esta função será usada pelo Flask-HTTPAuth para verificar a senha quando a autenticação básica for necessária (graças ao @basic_auth.verify_passworddecorador).

Além disso, um manipulador de erros é definido para a autenticação básica que retorna informações sobre o erro no formato JSON.

Para a autenticação do token (processando um token para determinar se o usuário é válido):

@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

A verify_token()função é usada para verificar se um token de autenticação é válido. Esta função será usada pelo Flask-HTTPAuth para verificar o token quando a autenticação do token for necessária (graças ao @token_auth.verify_tokendecorador).

Além disso, um manipulador de erros é definido para a autenticação de token que retorna informações sobre o erro no formato JSON.

Rotas de usuários

No users_api_blueprint, haverá duas rotas:

  1. Cadastrando um novo usuário
  2. Recuperando um token de autenticação

Para começar, um novo conjunto de esquemas (usando marshmallow) precisa ser definido em projects/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()

Esses esquemas serão usados ​​para definir as entradas e saídas para as funções de visualização definidas neste arquivo.

Cadastrando um novo usuário

Em seguida, defina a função de visualização para registrar um novo usuário:

@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

Adicione as importações:

from apifairy import authenticate, body, other_responses, response

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

Esse endpoint da API usa o new_user_schemapara especificar que o email e a senha são as entradas.

OBSERVAÇÃO: como o email e a senha são enviados para esse endpoint da API, é um bom momento para lembrar que o uso de HTTP é aceitável durante o teste de desenvolvimento, mas HTTPS (seguro) sempre deve ser usado na produção.

O email e a senha (definidos como os kwargsargumentos da palavra-chave -) são então descompactados para criar um novo Userobjeto, que é salvo no banco de dados:

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

A saída do endpoint da API é definida por user_schema, que é o ID e o email do novo usuário.

Recuperando um token de autenticação

A outra função de visualização a ser definida em projects/users_api/routes.py é para recuperar o token de autenticação:

@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)

O @authenticatedecorador é usado pela primeira vez neste tutorial e especifica que a autenticação básica deve ser usada para proteger esta rota:

@authenticate(basic_auth)

Quando o usuário deseja recuperar seu token de autenticação, ele precisa enviar uma solicitação POST para esse endpoint da API com o email e a senha incorporados no cabeçalho 'Authorization'. Como exemplo, o seguinte comando Python usando o pacote Requests pode ser feito para este endpoint da API:

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

Se a autenticação básica for bem-sucedida, a função de visualização recupera o usuário atual usando o current_user()método fornecido pelo Flask-HTTPAuth:

user = basic_auth.current_user()

Um novo token de autenticação é criado para esse usuário:

token = user.generate_auth_token()

E esse token é salvo no banco de dados para que possa ser usado para autenticar o usuário no futuro (pelo menos pelos próximos 60 minutos!).

Por fim, o novo token de autenticação é retornado para o usuário salvar para todas as chamadas de API subsequentes.

Atualizações de endpoints da API

Com um processo de autenticação em vigor, é hora de adicionar alguns guardas aos terminais de API existentes para garantir que apenas usuários válidos possam acessar o aplicativo.

Essas atualizações são para as funções de visualização definidas em projects/journal_api/routes.py .

Primeiro, atualize journal()para retornar apenas as entradas de diário do usuário atual:

@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()

Atualize as importações no topo da seguinte forma:

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

O @authenticatedecorador especifica que a autenticação de token precisa ser usada ao acessar esse endpoint da API. Como exemplo, a seguinte solicitação GET pode ser feita usando Requests ( após a recuperação do token de autenticação ):

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

Depois que o usuário é autenticado, a lista completa de entradas de diário é recuperada do banco de dados com base no ID do usuário:

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

A saída desse endpoint da API é definida pelo @responsedecorador, que é uma lista de entradas de diário (ID, entrada, ID do usuário).

A seguir, atualize 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

Assim como na função de visualização anterior, o @authenticatedecorador é usado para especificar que a autenticação de token precisa ser usada ao acessar esse endpoint da API. Além disso, a entrada de diário agora é adicionada especificando o ID do usuário que deve ser associado à entrada de diário:

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

A nova entrada de diário é salva no banco de dados e a entrada de diário é retornada (conforme definido pelo @responsedecorador).

A seguir, atualize 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

O @authenticatedecorador é adicionado para especificar que a autenticação de token é necessária para acessar esse endpoint da API.

Ao tentar recuperar uma entrada de diário, uma verificação adicional é adicionada para garantir que o usuário que está tentando acessar a entrada de diário seja o "proprietário" real da entrada. Caso contrário, um código de erro 403 (Proibido) é retornado por meio da abort()função do Flask:

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

Observe que este endpoint de API tem duas respostas fora do nominal especificadas pelo @other_responsesdecorador:

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

Lembrete: O @other_responsesdecorador serve apenas para documentação; é responsabilidade da função view gerar esses erros.

A seguir, atualize 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

As atualizações desta função de visualização são semelhantes às outras funções de visualização nesta seção:

  1. @authenticatedecorador especifica que a autenticação de token é necessária para acessar este endpoint da API
  2. Somente o usuário que "possui" o lançamento contábil manual tem permissão para atualizar o lançamento (caso contrário, 403 (Proibido))

Por fim, atualize 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

Conclusão

Este tutorial forneceu um passo a passo de como construir uma API de maneira fácil e rápida no Flask usando APIFairy.

Os decoradores são a chave para definir os endpoints da API:

  • Entradas :
    • @arguments- argumentos de entrada da string de consulta da URL
    • @body- estrutura da solicitação JSON
  • Saídas :
    • @response- estrutura da resposta JSON
  • Autenticação :
    • @authenticate- abordagem de autenticação usando Flask-HTTPAuth
  • Erros :
    • @other_responses- respostas fora do nominal, como códigos de erro HTTP

Além disso, a documentação da API gerada pelo APIFairy é excelente e fornece informações importantes para os usuários do aplicativo.

Fonte:  https://testdrive.io

#api #flask 

What is GEEK

Buddha Community

Como Criar Facilmente Uma API RESTful Com Flask E 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