diff --git a/server/app/apis/__init__.py b/server/app/apis/__init__.py
index 7ba6eb54ec6db8a86c282ef00a131748f06033c3..c5395c7cddb2256b4b209f7a139c2f09ce4a5b4d 100644
--- a/server/app/apis/__init__.py
+++ b/server/app/apis/__init__.py
@@ -132,6 +132,7 @@ flask_api = Api()
 
 def init_api():
 
+    from .alternatives import blp as alternative_blp
     from .auth import blp as auth_blp
     from .codes import blp as code_blp
     from .competitions import blp as competition_blp
@@ -151,3 +152,4 @@ def init_api():
     flask_api.register_blueprint(question_blp)
     flask_api.register_blueprint(team_blp)
     flask_api.register_blueprint(code_blp)
+    flask_api.register_blueprint(alternative_blp)
diff --git a/server/app/apis/alternatives.py b/server/app/apis/alternatives.py
index d3ae5d9d4be9f3a5835c4bb4c6f00ee5c38aa34d..a3143a7cea6093d1fe9d06210f780c7930c70f1d 100644
--- a/server/app/apis/alternatives.py
+++ b/server/app/apis/alternatives.py
@@ -3,79 +3,84 @@ All API calls concerning question alternatives.
 Default route: /api/competitions/<competition_id>/slides/<slide_id>/questions/<question_id>/alternatives
 """
 
-from os import abort
 
-import app.core.http_codes as codes
 import app.database.controller as dbc
-from app.apis import item_response, list_response, protect_route
-from app.core.dto import QuestionAlternativeDTO
-from app.core.parsers import sentinel
+from app.apis import protect_route
+from app.core import ma
+from app.core.schemas import BaseSchema, QuestionAlternativeSchema
+from app.database import models
 from app.database.models import Question, QuestionAlternative
-from flask_restx import Resource, reqparse
+from flask.views import MethodView
+from flask_smorest import Blueprint, abort
 
-api = QuestionAlternativeDTO.api
-schema = QuestionAlternativeDTO.schema
-list_schema = QuestionAlternativeDTO.list_schema
+from . import http_codes
 
-alternative_parser_add = reqparse.RequestParser()
-alternative_parser_add.add_argument("alternative", type=str, default="", location="json")
-alternative_parser_add.add_argument("correct", type=str, default="", location="json")
+blp = Blueprint(
+    "alternative",
+    "alternative",
+    url_prefix="/api/competitions/<competition_id>/slides/<slide_id>/questions/<question_id>/alternatives",
+    description="Adding, updating, deleting and copy alternatives",
+)
 
-alternative_parser_edit = reqparse.RequestParser()
-alternative_parser_edit.add_argument("alternative", type=str, default=sentinel, location="json")
-alternative_parser_edit.add_argument("alternative_order", type=int, default=sentinel, location="json")
-alternative_parser_edit.add_argument("correct", type=str, default=sentinel, location="json")
-alternative_parser_edit.add_argument("correct_order", type=int, default=sentinel, location="json")
 
+class AlternativeAddArgsSchema(BaseSchema):
+    class Meta(BaseSchema.Meta):
+        model = models.QuestionAlternative
 
-@api.route("")
-@api.param("competition_id, slide_id, question_id")
-class QuestionAlternativeList(Resource):
+    alternative = ma.auto_field(required=False, missing="")
+    correct = ma.auto_field(required=False, missing="")
+
+
+class AlternativeEditArgsSchema(BaseSchema):
+    class Meta(BaseSchema.Meta):
+        model = models.QuestionAlternative
+
+    alternative = ma.auto_field(required=False)
+    alternative_order = ma.auto_field(required=False, missing=None)
+    correct = ma.auto_field(required=False)
+    correct_order = ma.auto_field(required=False, missing=None)
+
+
+@blp.route("")
+class Alternatives(MethodView):
     @protect_route(allowed_roles=["*"], allowed_views=["*"])
+    @blp.response(http_codes.OK, QuestionAlternativeSchema(many=True))
     def get(self, competition_id, slide_id, question_id):
         """ Gets the all question alternatives to the specified question. """
-
-        items = dbc.get.question_alternative_list(
-            competition_id,
-            slide_id,
-            question_id,
-        )
-        return list_response(list_schema.dump(items))
+        return dbc.get.question_alternative_list(competition_id, slide_id, question_id)
 
     @protect_route(allowed_roles=["*"])
-    def post(self, competition_id, slide_id, question_id):
+    @blp.arguments(AlternativeAddArgsSchema)
+    @blp.response(http_codes.OK, QuestionAlternativeSchema)
+    @blp.alt_response(http_codes.CONFLICT, None, description="Could not add alternative")
+    def post(self, args, competition_id, slide_id, question_id):
         """
         Posts a new question alternative to the specified
         question using the provided arguments.
         """
-
-        args = alternative_parser_add.parse_args(strict=True)
-        item = dbc.add.question_alternative(**args, question_id=question_id)
-        return item_response(schema.dump(item))
+        return dbc.add.question_alternative(**args, question_id=question_id)
 
 
-@api.route("/<alternative_id>")
-@api.param("competition_id, slide_id, question_id, alternative_id")
-class QuestionAlternatives(Resource):
+@blp.route("/<alternative_id>")
+class QuestionAlternatives(MethodView):
     @protect_route(allowed_roles=["*"], allowed_views=["*"])
+    @blp.response(http_codes.OK, QuestionAlternativeSchema)
+    @blp.alt_response(http_codes.NOT_FOUND, None, description="Could not find alternative")
     def get(self, competition_id, slide_id, question_id, alternative_id):
         """ Gets the specified question alternative. """
-
-        items = dbc.get.question_alternative(
-            competition_id,
-            slide_id,
-            question_id,
-            alternative_id,
-        )
-        return item_response(schema.dump(items))
+        return dbc.get.question_alternative(competition_id, slide_id, question_id, alternative_id)
 
     @protect_route(allowed_roles=["*"])
-    def put(self, competition_id, slide_id, question_id, alternative_id):
+    @blp.arguments(AlternativeEditArgsSchema)
+    @blp.response(http_codes.OK, QuestionAlternativeSchema)
+    @blp.alt_response(http_codes.BAD_REQUEST, None, description="Paramters to edit alternative with is incorrect")
+    @blp.alt_response(http_codes.NOT_FOUND, None, description="Could not find alternative")
+    @blp.alt_response(http_codes.CONFLICT, None, description="Could not edit alternative with the given values")
+    def put(self, args, competition_id, slide_id, question_id, alternative_id):
         """
         Edits the specified question alternative using the provided arguments.
         """
 
-        args = alternative_parser_edit.parse_args(strict=True)
         item = dbc.get.question_alternative(
             competition_id,
             slide_id,
@@ -84,9 +89,12 @@ class QuestionAlternatives(Resource):
         )
 
         new_alternative_order = args.pop("alternative_order")
-        if new_alternative_order is not sentinel and item.alternative_order != new_alternative_order:
+        if new_alternative_order is not None and item.alternative_order != new_alternative_order:
             if not (0 <= new_alternative_order < dbc.utils.count(QuestionAlternative, {"question_id": question_id})):
-                abort(codes.BAD_REQUEST, f"Cant change to invalid slide order '{new_alternative_order}'")
+                abort(
+                    http_codes.BAD_REQUEST,
+                    message=f"Kan inte ändra till ogiltigt sidordning '{new_alternative_order}'",
+                )
 
             item_question = dbc.get.one(Question, question_id)
             dbc.utils.move_order(
@@ -94,25 +102,20 @@ class QuestionAlternatives(Resource):
             )
 
         new_correct_order = args.pop("correct_order")
-        if new_correct_order is not sentinel and item.correct_order != new_correct_order:
+        if new_correct_order is not None and item.correct_order != new_correct_order:
             if not (0 <= new_correct_order < dbc.utils.count(QuestionAlternative, {"question_id": question_id})):
-                abort(codes.BAD_REQUEST, f"Cant change to invalid slide order '{new_correct_order}'")
+                abort(http_codes.BAD_REQUEST, message=f"Kan inte ändra till ogiltigt sidordning '{new_correct_order}'")
 
             item_question = dbc.get.one(Question, question_id)
             dbc.utils.move_order(item_question.alternatives, "correct_order", item.correct_order, new_correct_order)
 
-        item = dbc.edit.default(item, **args)
-        return item_response(schema.dump(item))
+        return dbc.edit.default(item, **args)
 
     @protect_route(allowed_roles=["*"])
+    @blp.response(http_codes.NO_CONTENT, None)
+    @blp.alt_response(http_codes.NOT_FOUND, None, description="Could not find alternative")
+    @blp.alt_response(http_codes.CONFLICT, None, description="Could not delete alternative")
     def delete(self, competition_id, slide_id, question_id, alternative_id):
         """ Deletes the specified question alternative. """
-
-        item = dbc.get.question_alternative(
-            competition_id,
-            slide_id,
-            question_id,
-            alternative_id,
-        )
-        dbc.delete.default(item)
-        return {}, codes.NO_CONTENT
+        dbc.delete.default(dbc.get.question_alternative(competition_id, slide_id, question_id, alternative_id))
+        return None