pythonvisual-studio-codeflask-smorest

Error on docker ValueError: The name 'Items' is already registered for this blueprint. Use 'name=' to provide a unique name


I am currently building an API on VS Code using Python 3.11, Flask, Insomnia, and Docker.

when I tried to create my resources file to use flask_smorest I am getting this error on Docker

ValueError: The name 'Items' is already registered for this blueprint. Use 'name=' to provide a unique name.

Insomnia is also giving me a value error indicating "Items" is already registered for this blueprint.

I am learning right now and am not sure how to find out where the blueprint is being used twice so that I can change it and move forward with my course.

Thanks!

app.py file: `

from flask import Flask
from flask_smorest import Api
from resources.item import blp as ItemBlueprint
from resources.item import blp as StoreBlueprint

app = Flask(__name__)

app.config["PROPAGATE_EXCEPTIONS"] = True
app.config["API_TITLE"] = "Stores REST API"
app.config["API_VERSION"] = "v1"
app.config["OPENAPI_VERSION"] = "3.0.3"
app.config["OPENAPI_URL_PREFIX"] = "/"
app.config["OPENAPI_SWAGGER_UI_PATH"] = "/swagger-ui"
app.config["OPENAPI_SWAGGER_UI_URL"] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist/"

api = Api(app)

api.register_blueprint(ItemBlueprint)
api.register_blueprint(StoreBlueprint)

`

store.py file: `

import uuid
from flask import request
from flask.views import MethodView
from flask_smorest import Blueprint, abort
from db import stores


blp = Blueprint("Stores", __name__, description="Operations on stores")

@blp.route("/store/<string:store_id>")
class Store(MethodView):
    def get(self, store_id):
        try:
        # Here you might also want to add the items in this store
        # We'll do that later on in the course
            return stores[store_id]
    
        except KeyError:
            abort(404, message="Store not found.")

    def delete(self, store_id):
        try:
            del stores[store_id]
            return {"message": "Store deleted."}
    
        except KeyError:
            abort(404, message="Store not found.")

@blp.route("/store")
class Store(MethodView):
    def get(self):
        return {"stores": list(stores.values())}

    def post(self):  # sourcery skip: remove-redundant-fstring
        store_data = request.get_json()
        if "name" not in store_data:
            abort(
            400,
            message="Bad request. Ensure 'name' is included in the JSON payload.",
        )
        for store in stores.values():
            if store_data["name"] == store["name"]:
                abort(400, message=f"Store already exists.")

        store_id = uuid.uuid4().hex
        store = {**store_data, "id": store_id}
        stores[store_id] = store

        return store 

`

item.py file: `

import uuid
from flask import request
from flask.views import MethodView
from flask_smorest import Blueprint, abort
from db import items


blp = Blueprint("Items", __name__, description="Operations on items")

@blp.route("/item/<string:item_id>")
class Item(MethodView):
    def get(self, item_id):
        try:
        # Here you might also want to add the items in this store
        # We'll do that later on in the course
            return items[item_id]
    
        except KeyError:
            abort(404, message="Item not found.")

    def delete(self, item_id):
        try:
            del items[item_id]
            return {"message": "Item deleted."}
    
        except KeyError:
            abort(404, message="Item not found.")

    def put(self, item_id):
        item_data = request.get_json()
        # There's  more validation to do here!
        # Like making sure price is a number, and also both items are optional
        # Difficult to do with an if statement...
        if "price" not in item_data or "name" not in item_data:
            abort(
            400,
            message="Bad request. Ensure 'price', and 'name' are included in the JSON payload.",
        )
        try:
            item = items[item_id]

        # https://blog.teclado.com/python-dictionary-merge-update-operators/
            item |= item_data

            return item
        except KeyError:
            abort(404, message="Item not found.")


@blp.route("/item")
class ItemList(MethodView):
    def get(self):
        return {"items": list(items.values())}

    def post(self):  # sourcery skip: remove-redundant-fstring
        item_data = request.get_json()
        if "name" not in item_data:
            abort(
            400,
            message="Bad request. Ensure 'name' is included in the JSON payload.",
        )
        for item in items.values():
            if item_data["name"] == item["name"]:
                abort(400, message=f"Item already exists.")

        item_id = uuid.uuid4().hex
        item = {**item_data, "id": item_id}
        items[item_id] = item

        return item 

`

I am not sure how to find out where the first blueprint was created or how I duplicated the blueprint anywhere in the above code. I am hoping someone can offer assistance.

I have restarted this part so many times already!


Solution

  • In app.py:

    from resources.item import blp as ItemBlueprint
    from resources.item import blp as StoreBlueprint
    

    you're importing (and later, registering) the same blueprint twice. Do instead:

    from resources.item import blp as ItemBlueprint
    from resources.store import blp as StoreBlueprint