@@ -654,174 +654,170 @@ def handler(
654
654
def test_openapi_file_upload_parameters ():
655
655
"""Test File parameter generates correct OpenAPI schema for file uploads."""
656
656
from aws_lambda_powertools .event_handler .openapi .params import _File , _Form
657
-
657
+
658
658
app = APIGatewayRestResolver (enable_validation = True )
659
659
660
660
@app .post ("/upload" )
661
661
def upload_file (
662
662
file : Annotated [bytes , _File (description = "File to upload" )],
663
- filename : Annotated [str , _Form (description = "Name of the file" )]
663
+ filename : Annotated [str , _Form (description = "Name of the file" )],
664
664
):
665
665
return {"message" : f"Uploaded { filename } " , "size" : len (file )}
666
666
667
667
schema = app .get_openapi_schema ()
668
-
668
+
669
669
# Check that the endpoint is present
670
670
assert "/upload" in schema .paths
671
-
671
+
672
672
post_op = schema .paths ["/upload" ].post
673
673
assert post_op is not None
674
-
674
+
675
675
# Check request body
676
676
request_body = post_op .requestBody
677
677
assert request_body is not None
678
678
assert request_body .required is True
679
-
679
+
680
680
# Check content type is multipart/form-data
681
681
assert "multipart/form-data" in request_body .content
682
-
682
+
683
683
# Get the schema reference
684
684
multipart_content = request_body .content ["multipart/form-data" ]
685
685
assert multipart_content .schema_ is not None
686
-
686
+
687
687
# Check that it references a component schema
688
688
schema_ref = multipart_content .schema_ .ref
689
689
assert schema_ref is not None
690
690
assert schema_ref .startswith ("#/components/schemas/" )
691
-
691
+
692
692
# Get the component schema name
693
693
component_name = schema_ref .split ("/" )[- 1 ]
694
694
assert component_name in schema .components .schemas
695
-
695
+
696
696
# Check the component schema properties
697
697
component_schema = schema .components .schemas [component_name ]
698
698
properties = component_schema .properties
699
-
699
+
700
700
# Check file parameter
701
701
assert "file" in properties
702
702
file_prop = properties ["file" ]
703
703
assert file_prop .type == "string"
704
704
assert file_prop .format == "binary" # This is the key assertion
705
705
assert file_prop .title == "File"
706
706
assert file_prop .description == "File to upload"
707
-
707
+
708
708
# Check form parameter
709
709
assert "filename" in properties
710
710
filename_prop = properties ["filename" ]
711
711
assert filename_prop .type == "string"
712
712
assert filename_prop .title == "Filename"
713
713
assert filename_prop .description == "Name of the file"
714
-
714
+
715
715
# Check required fields
716
716
assert component_schema .required == ["file" , "filename" ]
717
717
718
718
719
719
def test_openapi_form_only_parameters ():
720
720
"""Test Form parameters generate application/x-www-form-urlencoded content type."""
721
721
from aws_lambda_powertools .event_handler .openapi .params import _Form
722
-
722
+
723
723
app = APIGatewayRestResolver (enable_validation = True )
724
724
725
725
@app .post ("/form-data" )
726
726
def create_form_data (
727
727
name : Annotated [str , _Form (description = "User name" )],
728
- email :
Annotated [
str ,
_Form (
description = "User email" )]
= "[email protected] "
728
+ email :
Annotated [
str ,
_Form (
description = "User email" )]
= "[email protected] " ,
729
729
):
730
730
return {"name" : name , "email" : email }
731
731
732
732
schema = app .get_openapi_schema ()
733
-
733
+
734
734
# Check that the endpoint is present
735
735
assert "/form-data" in schema .paths
736
-
736
+
737
737
post_op = schema .paths ["/form-data" ].post
738
738
assert post_op is not None
739
-
739
+
740
740
# Check request body
741
741
request_body = post_op .requestBody
742
742
assert request_body is not None
743
-
743
+
744
744
# Check content type is application/x-www-form-urlencoded
745
745
assert "application/x-www-form-urlencoded" in request_body .content
746
-
746
+
747
747
# Get the schema reference
748
748
form_content = request_body .content ["application/x-www-form-urlencoded" ]
749
749
assert form_content .schema_ is not None
750
-
750
+
751
751
# Check that it references a component schema
752
752
schema_ref = form_content .schema_ .ref
753
753
assert schema_ref is not None
754
754
assert schema_ref .startswith ("#/components/schemas/" )
755
-
755
+
756
756
# Get the component schema
757
757
component_name = schema_ref .split ("/" )[- 1 ]
758
758
assert component_name in schema .components .schemas
759
-
759
+
760
760
component_schema = schema .components .schemas [component_name ]
761
761
properties = component_schema .properties
762
-
762
+
763
763
# Check form parameters
764
764
assert "name" in properties
765
765
name_prop = properties ["name" ]
766
766
assert name_prop .type == "string"
767
767
assert name_prop .description == "User name"
768
-
768
+
769
769
assert "email" in properties
770
770
email_prop = properties ["email" ]
771
771
assert email_prop .type == "string"
772
772
assert email_prop .description == "User email"
773
773
assert email_prop .
default == "[email protected] "
774
-
774
+
775
775
# Check required fields (only name should be required since email has default)
776
776
assert component_schema .required == ["name" ]
777
777
778
778
779
779
def test_openapi_mixed_file_and_form_parameters ():
780
780
"""Test mixed File and Form parameters use multipart/form-data."""
781
781
from aws_lambda_powertools .event_handler .openapi .params import _File , _Form
782
-
782
+
783
783
app = APIGatewayRestResolver (enable_validation = True )
784
784
785
785
@app .post ("/mixed" )
786
786
def upload_with_metadata (
787
787
file : Annotated [bytes , _File (description = "Document to upload" )],
788
788
title : Annotated [str , _Form (description = "Document title" )],
789
- category : Annotated [str , _Form (description = "Document category" )] = "general"
789
+ category : Annotated [str , _Form (description = "Document category" )] = "general" ,
790
790
):
791
- return {
792
- "title" : title ,
793
- "category" : category ,
794
- "file_size" : len (file )
795
- }
791
+ return {"title" : title , "category" : category , "file_size" : len (file )}
796
792
797
793
schema = app .get_openapi_schema ()
798
-
794
+
799
795
# Check that the endpoint is present
800
796
assert "/mixed" in schema .paths
801
-
797
+
802
798
post_op = schema .paths ["/mixed" ].post
803
799
request_body = post_op .requestBody
804
-
800
+
805
801
# When both File and Form parameters are present, should use multipart/form-data
806
802
assert "multipart/form-data" in request_body .content
807
-
803
+
808
804
# Get the component schema
809
805
multipart_content = request_body .content ["multipart/form-data" ]
810
806
schema_ref = multipart_content .schema_ .ref
811
807
component_name = schema_ref .split ("/" )[- 1 ]
812
808
component_schema = schema .components .schemas [component_name ]
813
-
809
+
814
810
properties = component_schema .properties
815
-
811
+
816
812
# Check file parameter has binary format
817
813
assert "file" in properties
818
814
file_prop = properties ["file" ]
819
815
assert file_prop .format == "binary"
820
-
816
+
821
817
# Check form parameters are present
822
818
assert "title" in properties
823
819
assert "category" in properties
824
-
820
+
825
821
# Check required fields
826
822
assert "file" in component_schema .required
827
823
assert "title" in component_schema .required
@@ -831,48 +827,48 @@ def upload_with_metadata(
831
827
def test_openapi_multiple_file_uploads ():
832
828
"""Test multiple file uploads with List[bytes] type."""
833
829
from aws_lambda_powertools .event_handler .openapi .params import _File , _Form
834
-
830
+
835
831
app = APIGatewayRestResolver (enable_validation = True )
836
832
837
833
@app .post ("/upload-multiple" )
838
834
def upload_multiple_files (
839
835
files : Annotated [List [bytes ], _File (description = "Files to upload" )],
840
- description : Annotated [str , _Form (description = "Upload description" )]
836
+ description : Annotated [str , _Form (description = "Upload description" )],
841
837
):
842
838
return {
843
839
"message" : f"Uploaded { len (files )} files" ,
844
840
"description" : description ,
845
- "total_size" : sum (len (file ) for file in files )
841
+ "total_size" : sum (len (file ) for file in files ),
846
842
}
847
843
848
844
schema = app .get_openapi_schema ()
849
-
845
+
850
846
# Check that the endpoint is present
851
847
assert "/upload-multiple" in schema .paths
852
-
848
+
853
849
post_op = schema .paths ["/upload-multiple" ].post
854
850
request_body = post_op .requestBody
855
-
851
+
856
852
# Should use multipart/form-data for file uploads
857
853
assert "multipart/form-data" in request_body .content
858
-
854
+
859
855
# Get the component schema
860
856
multipart_content = request_body .content ["multipart/form-data" ]
861
857
schema_ref = multipart_content .schema_ .ref
862
858
component_name = schema_ref .split ("/" )[- 1 ]
863
859
component_schema = schema .components .schemas [component_name ]
864
-
860
+
865
861
properties = component_schema .properties
866
-
862
+
867
863
# Check files parameter
868
864
assert "files" in properties
869
865
files_prop = properties ["files" ]
870
-
866
+
871
867
# For List[bytes] with File annotation, should be array of strings with binary format
872
868
assert files_prop .type == "array"
873
869
assert files_prop .items .type == "string"
874
870
assert files_prop .items .format == "binary"
875
-
871
+
876
872
# Check form parameter
877
873
assert "description" in properties
878
874
description_prop = properties ["description" ]
@@ -882,38 +878,38 @@ def upload_multiple_files(
882
878
def test_openapi_public_file_form_exports ():
883
879
"""Test that File and Form are properly exported for public use."""
884
880
from aws_lambda_powertools .event_handler .openapi .params import File , Form
885
-
881
+
886
882
app = APIGatewayRestResolver (enable_validation = True )
887
883
888
884
@app .post ("/public-api" )
889
885
def upload_with_public_types (
890
886
file : File , # Using the public export
891
- name : Form # Using the public export
887
+ name : Form , # Using the public export
892
888
):
893
889
return {"status" : "uploaded" }
894
890
895
891
schema = app .get_openapi_schema ()
896
-
892
+
897
893
# Check that the endpoint works with public exports
898
894
assert "/public-api" in schema .paths
899
-
895
+
900
896
post_op = schema .paths ["/public-api" ].post
901
897
request_body = post_op .requestBody
902
-
898
+
903
899
# Should generate multipart/form-data
904
900
assert "multipart/form-data" in request_body .content
905
-
901
+
906
902
# Get the component schema
907
903
multipart_content = request_body .content ["multipart/form-data" ]
908
904
schema_ref = multipart_content .schema_ .ref
909
905
component_name = schema_ref .split ("/" )[- 1 ]
910
906
component_schema = schema .components .schemas [component_name ]
911
-
907
+
912
908
properties = component_schema .properties
913
-
909
+
914
910
# Check that both parameters are present and correctly typed
915
911
assert "file" in properties
916
912
assert properties ["file" ].format == "binary"
917
-
913
+
918
914
assert "name" in properties
919
915
assert properties ["name" ].type == "string"
0 commit comments