1
resposta

[Dúvida] Documentar com OpenAPI (SWAGGER)

Completei o CRUD, meu projeto tem apenas uma tabela e não tem controle de usuário, só desejo mesmo nesse momento documentar as rotas criadas. Meu arquivo app.py ficou assim: from flask import Flask, render_template, request, url_for, redirect, jsonify from flask_sqlalchemy import SQLAlchemy from flask_openapi3 import OpenAPI, Info, Tag from flask_cors import CORS import os

db_password = os.environ.get("DB_PASSWORD") db_user = os.environ.get("DB_USER")

info = Info( title="API Margem Certa", description="API para calcular a margem de contribuição de itens de venda.", version="0.0.1", openapi_version="3.0.0", doc="/app", url_prefix="/app", ) app = OpenAPI(name, info=info) CORS(app)

definindo tags

home_tag = Tag( name="Documentação", description="Seleção de documentação: Swagger, Redoc ou Rapidoc", ) mc_item_consulta = Tag( name="Margem Certa - Consultas de Itens", description="Visualiza lista de itens resumida ou detalhe de item", )

mc_item_adicao = Tag( name="Margem Certa - Novos Itens", description="Adiçao de itens na base de dados", ) mc_item_exclusao = Tag( name="Margem Certa - Exclusão de Itens", description="Exclusão de itens da base de dados por id", ) mc_item_edicao = Tag( name="Margem Certa Edição de Itens", description="Ediçao de itens da base de dados por id", )

conectar nossa aplicacao com o banco de dados

app.config[ "SQLALCHEMY_DATABASE_URI" ] = "{SGBD}://{usuario}:{senha}@{servidor}/{database}".format( SGBD="mysql+mysqlconnector", usuario=db_user, senha=db_password, servidor="127.0.0.1", database="db_margemcerta", )

db = SQLAlchemy(app) # instanciando nossa aplicação com o SQLAlchemy

criando a conexao com a tabela no SQLALCHEMY

class Tb_margemcerta(db.Model): ids = db.Column(db.Integer, primary_key=True, autoincrement=True) clientes = db.Column(db.String(60), nullable=False) descricoes = db.Column(db.String(120), nullable=False) propostas = db.Column(db.Integer(), nullable=False) itens = db.Column(db.Integer(), nullable=False) precos = db.Column(db.Float(10, 2), nullable=False) custos = db.Column(db.Float(10, 2), nullable=False) mc_abs = db.Column(db.Float(10, 2), nullable=False) mc_rel = db.Column(db.Float(5, 2), nullable=False)

def tb_margemcerta_dict(self):
    return {
        "ids": self.ids,
        "clientes": self.clientes,
        "descricoes": self.descricoes,
        "propostas": self.propostas,
        "itens": self.itens,
        "precos": self.precos,
        "custos": self.custos,
        "mc_abs": self.mc_abs,
        "mc_rel": self.mc_rel,
    }

def __repr__(self) -> str:
    return "<Name % r>" % self.name
    # return f"<Tb_margemcerta {self.clientes} - {self.descricoes}>"

@app.template_filter() def brl_format(value): value = float(value) return "{:,.2f}".format(value).replace(",", "v").replace(".", ",").replace("v", ".")

criando rotas

@app.get("/", tags=[home_tag]) def apidocs(): """ Redireciona para /openapi, tela que permite a escolha do estilo de documentação. """ return redirect("/openapi")

@app.get("/margemcerta") def home(): """ Retorna consulta de todos os itens da base. --- responses: '200': description: Sucesso

"""
lista = Tb_margemcerta.query.order_by(Tb_margemcerta.ids.desc())

lista_home = jsonify(
    [
        {
            "Cliente": item.clientes,
            "Descrição": item.descricoes,
            "Proposta": item.propostas,
            "Item": item.itens,
            "Preço": item.precos,
            "Margem Contrib. (%)": item.mc_rel,
        }
        for item in lista
    ]
)
return render_template("home.html", itens=lista)

... restante do codigo...

if __name__ == "__main__":
app.run(debug=True)

eu preciso que a saida seja mesmo essa (  return render_template("home.html", itens=lista)), assim renderizamos a página corretamente, mas quando vamos usar o swagger ui a saida que precisaria ser jason está sendo o proprio html eu gostaria que a saida fosse como da variavel lista_home quando fosse usado pelo swagger ui. 
1 resposta

Tranquilo, vou te dar uma mãozinha nisso!

Quando você está lidando com o Swagger UI, ele espera um formato específico de resposta em JSON para documentar suas rotas adequadamente. No seu caso, parece que você quer uma saída JSON quando acessa a rota pelo Swagger UI, mas ainda quer renderizar a página HTML quando acessa a rota diretamente pelo navegador.

Uma abordagem simples seria verificar se a requisição aceita JSON (ou seja, se é proveniente do Swagger UI) e, em seguida, retornar a resposta no formato JSON. Se não, você renderiza a página HTML como de costume.

from flask import request

# ... (código existente)

# Criando rotas
@app.get("/", tags=[home_tag])
def apidocs():
    """ Redireciona para /openapi, tela que permite a escolha do estilo de documentação. """
    return redirect("/openapi")

@app.get("/margemcerta")
def home():
    """ Retorna consulta de todos os itens da base. --- responses: '200': description: Sucesso """
    lista = Tb_margemcerta.query.order_by(Tb_margemcerta.ids.desc())

    lista_home = [
        {
            "Cliente": item.clientes,
            "Descrição": item.descricoes,
            "Proposta": item.propostas,
            "Item": item.itens,
            "Preço": item.precos,
            "Margem Contrib. (%)": item.mc_rel,
        }
        for item in lista
    ]

    if "application/json" in request.accept_mimetypes:
        # Se a requisição aceita JSON, retorna a lista no formato JSON
        return jsonify(lista_home)

    # Se não, renderiza a página HTML
    return render_template("home.html", itens=lista)

Essa modificação verifica se a requisição aceita o tipo MIME "application/json" e, se sim, retorna a lista_home como JSON. Se não, ele renderiza a página HTML como antes. Isso deve funcionar para fornecer a saída desejada no Swagger UI.