@@ -876,200 +876,191 @@ const resolver: Resolver = async (
876
876
endpoint,
877
877
pathBuilder,
878
878
} = directives . rest as RestLink . DirectiveOptions ;
879
+
879
880
const endpointOption = getEndpointOptions ( endpoints , endpoint ) ;
880
- try {
881
- const neitherPathsProvided = path == null && pathBuilder == null ;
881
+ const neitherPathsProvided = path == null && pathBuilder == null ;
882
882
883
- if ( neitherPathsProvided ) {
884
- throw new Error (
885
- `One of ("path" | "pathBuilder") must be set in the @rest() directive. This request had neither, please add one` ,
883
+ if ( neitherPathsProvided ) {
884
+ throw new Error (
885
+ `One of ("path" | "pathBuilder") must be set in the @rest() directive. This request had neither, please add one` ,
886
+ ) ;
887
+ }
888
+ if ( ! pathBuilder ) {
889
+ if ( ! path . includes ( ':' ) ) {
890
+ // Colons are the legacy route, and aren't uri encoded anyhow.
891
+ pathBuilder = PathBuilder . replacerForPath ( path ) ;
892
+ } else {
893
+ console . warn (
894
+ "Deprecated: '@rest(path:' contains a ':' colon, this format will be removed in future versions" ,
886
895
) ;
887
- }
888
- if ( ! pathBuilder ) {
889
- if ( ! path . includes ( ':' ) ) {
890
- // Colons are the legacy route, and aren't uri encoded anyhow.
891
- pathBuilder = PathBuilder . replacerForPath ( path ) ;
892
- } else {
893
- console . warn (
894
- "Deprecated: '@rest(path:' contains a ':' colon, this format will be removed in future versions" ,
895
- ) ;
896
896
897
- pathBuilder = ( {
898
- args,
899
- exportVariables,
900
- } : RestLink . PathBuilderProps ) : string => {
901
- const legacyArgs = {
902
- ...args ,
903
- ...exportVariables ,
904
- } ;
905
- const pathWithParams = Object . keys ( legacyArgs ) . reduce (
906
- ( acc , e ) => replaceLegacyParam ( acc , e , legacyArgs [ e ] ) ,
907
- path ,
908
- ) ;
909
- if ( pathWithParams . includes ( ':' ) ) {
910
- throw new Error (
911
- 'Missing parameters to run query, specify it in the query params or use ' +
912
- 'an export directive. (If you need to use ":" inside a variable string' +
913
- ' make sure to encode the variables properly using `encodeURIComponent' +
914
- '`. Alternatively see documentation about using pathBuilder.)' ,
915
- ) ;
916
- }
917
- return pathWithParams ;
897
+ pathBuilder = ( {
898
+ args,
899
+ exportVariables,
900
+ } : RestLink . PathBuilderProps ) : string => {
901
+ const legacyArgs = {
902
+ ...args ,
903
+ ...exportVariables ,
918
904
} ;
919
- }
920
- }
921
- const allParams : RestLink . PathBuilderProps = {
922
- args,
923
- exportVariables,
924
- context,
925
- '@rest' : directives . rest ,
926
- replacer : pathBuilder ,
927
- } ;
928
- const pathWithParams = pathBuilder ( allParams ) ;
929
-
930
- let {
931
- method,
932
- type,
933
- bodyBuilder,
934
- bodyKey,
935
- fieldNameDenormalizer : perRequestNameDenormalizer ,
936
- bodySerializer,
937
- } = directives . rest as RestLink . DirectiveOptions ;
938
- if ( ! method ) {
939
- method = 'GET' ;
940
- }
941
-
942
- let body = undefined ;
943
- let overrideHeaders : Headers = undefined ;
944
- if (
945
- - 1 === [ 'GET' , 'DELETE' ] . indexOf ( method ) &&
946
- operationType === 'mutation'
947
- ) {
948
- // Prepare our body!
949
- if ( ! bodyBuilder ) {
950
- // By convention GraphQL recommends mutations having a single argument named "input"
951
- // https://dev-blog.apollodata.com/designing-graphql-mutations-e09de826ed97
952
-
953
- const maybeBody =
954
- allParams . exportVariables [ bodyKey || 'input' ] ||
955
- allParams . args [ bodyKey || 'input' ] ;
956
- if ( ! maybeBody ) {
905
+ const pathWithParams = Object . keys ( legacyArgs ) . reduce (
906
+ ( acc , e ) => replaceLegacyParam ( acc , e , legacyArgs [ e ] ) ,
907
+ path ,
908
+ ) ;
909
+ if ( pathWithParams . includes ( ':' ) ) {
957
910
throw new Error (
958
- '[GraphQL mutation using a REST call without a body]. No `input` was detected. Pass bodyKey, or bodyBuilder to the @rest() directive to resolve this.' ,
911
+ 'Missing parameters to run query, specify it in the query params or use ' +
912
+ 'an export directive. (If you need to use ":" inside a variable string' +
913
+ ' make sure to encode the variables properly using `encodeURIComponent' +
914
+ '`. Alternatively see documentation about using pathBuilder.)' ,
959
915
) ;
960
916
}
917
+ return pathWithParams ;
918
+ } ;
919
+ }
920
+ }
921
+ const allParams : RestLink . PathBuilderProps = {
922
+ args,
923
+ exportVariables,
924
+ context,
925
+ '@rest' : directives . rest ,
926
+ replacer : pathBuilder ,
927
+ } ;
928
+ const pathWithParams = pathBuilder ( allParams ) ;
961
929
962
- bodyBuilder = ( argsWithExport : object ) => {
963
- return maybeBody ;
964
- } ;
965
- }
966
- body = convertObjectKeys (
967
- bodyBuilder ( allParams ) ,
968
- perRequestNameDenormalizer ||
969
- linkLevelNameDenormalizer ||
970
- noOpNameNormalizer ,
971
- ) ;
972
-
973
- let serializedBody : RestLink . SerializedBody ;
930
+ let {
931
+ method,
932
+ type,
933
+ bodyBuilder,
934
+ bodyKey,
935
+ fieldNameDenormalizer : perRequestNameDenormalizer ,
936
+ bodySerializer,
937
+ } = directives . rest as RestLink . DirectiveOptions ;
938
+ if ( ! method ) {
939
+ method = 'GET' ;
940
+ }
974
941
975
- if ( typeof bodySerializer === 'string' ) {
976
- if ( ! serializers . hasOwnProperty ( bodySerializer ) ) {
977
- throw new Error (
978
- '"bodySerializer" must correspond to configured serializer. ' +
979
- `Please make sure to specify a serializer called ${ bodySerializer } in the "bodySerializers" property of the RestLink.` ,
980
- ) ;
981
- }
982
- serializedBody = serializers [ bodySerializer ] ( body , headers ) ;
983
- } else {
984
- serializedBody = bodySerializer
985
- ? bodySerializer ( body , headers )
986
- : serializers [ DEFAULT_SERIALIZER_KEY ] ( body , headers ) ;
942
+ let body = undefined ;
943
+ let overrideHeaders : Headers = undefined ;
944
+ if (
945
+ - 1 === [ 'GET' , 'DELETE' ] . indexOf ( method ) &&
946
+ operationType === 'mutation'
947
+ ) {
948
+ // Prepare our body!
949
+ if ( ! bodyBuilder ) {
950
+ // By convention GraphQL recommends mutations having a single argument named "input"
951
+ // https://dev-blog.apollodata.com/designing-graphql-mutations-e09de826ed97
952
+
953
+ const maybeBody =
954
+ allParams . exportVariables [ bodyKey || 'input' ] ||
955
+ allParams . args [ bodyKey || 'input' ] ;
956
+ if ( ! maybeBody ) {
957
+ throw new Error (
958
+ '[GraphQL mutation using a REST call without a body]. No `input` was detected. Pass bodyKey, or bodyBuilder to the @rest() directive to resolve this.' ,
959
+ ) ;
987
960
}
988
961
989
- body = serializedBody . body ;
990
- overrideHeaders = new Headers ( serializedBody . headers ) ;
962
+ bodyBuilder = ( argsWithExport : object ) => {
963
+ return maybeBody ;
964
+ } ;
991
965
}
966
+ body = convertObjectKeys (
967
+ bodyBuilder ( allParams ) ,
968
+ perRequestNameDenormalizer ||
969
+ linkLevelNameDenormalizer ||
970
+ noOpNameNormalizer ,
971
+ ) ;
992
972
993
- validateRequestMethodForOperationType ( method , operationType || 'query' ) ;
994
- return await ( customFetch || fetch ) (
995
- `${ endpointOption . uri } ${ pathWithParams } ` ,
996
- {
997
- method,
998
- headers : overrideHeaders || headers ,
999
- body : body ,
1000
-
1001
- // Only set credentials if they're non-null as some browsers throw an exception:
1002
- // https://github.com/apollographql/apollo-link-rest/issues/121#issuecomment-396049677
1003
- ...( credentials ? { credentials } : { } ) ,
1004
- } ,
1005
- )
1006
- . then ( async res => {
1007
- context . responses . push ( res ) ;
1008
-
1009
- // All other success responses
1010
- if ( res . status < 300 ) {
1011
- // HTTP-204 means "no-content", similarly Content-Length implies the same
1012
- // This commonly occurs when you POST/PUT to the server, and it acknowledges
1013
- // success, but doesn't return your Resource.
1014
- if ( res . status === 204 || res . headers . get ( 'Content-Length' ) === '0' ) {
1015
- return Promise . resolve ( { } ) ;
1016
- }
1017
-
1018
- return res . json ( ) ;
1019
- }
973
+ let serializedBody : RestLink . SerializedBody ;
1020
974
1021
- // In a GraphQL context a missing resource should be indicated by
1022
- // a null value rather than throwing a network error
1023
- if ( res . status === 404 ) {
1024
- return Promise . resolve ( null ) ;
1025
- }
1026
- // Default error handling:
1027
- // Throw a JSError, that will be available under the
1028
- // "Network error" category in apollo-link-error
1029
- let parsed : any ;
1030
- // responses need to be cloned as they can only be read once
1031
- try {
1032
- parsed = await res . clone ( ) . json ( ) ;
1033
- } catch ( error ) {
1034
- // its not json
1035
- parsed = await res . clone ( ) . text ( ) ;
1036
- }
1037
- rethrowServerSideError (
1038
- res ,
1039
- parsed ,
1040
- `Response not successful: Received status code ${ res . status } ` ,
975
+ if ( typeof bodySerializer === 'string' ) {
976
+ if ( ! serializers . hasOwnProperty ( bodySerializer ) ) {
977
+ throw new Error (
978
+ '"bodySerializer" must correspond to configured serializer. ' +
979
+ `Please make sure to specify a serializer called ${ bodySerializer } in the "bodySerializers" property of the RestLink.` ,
1041
980
) ;
1042
- } )
1043
- . then ( result => {
1044
- if ( endpointOption . responseTransformer ) {
1045
- return endpointOption . responseTransformer ( result , type ) ;
1046
- }
981
+ }
982
+ serializedBody = serializers [ bodySerializer ] ( body , headers ) ;
983
+ } else {
984
+ serializedBody = bodySerializer
985
+ ? bodySerializer ( body , headers )
986
+ : serializers [ DEFAULT_SERIALIZER_KEY ] ( body , headers ) ;
987
+ }
1047
988
1048
- if ( responseTransformer ) {
1049
- return responseTransformer ( result , type ) ;
1050
- }
989
+ body = serializedBody . body ;
990
+ overrideHeaders = new Headers ( serializedBody . headers ) ;
991
+ }
1051
992
1052
- return result ;
1053
- } )
1054
- . then (
1055
- result =>
1056
- fieldNameNormalizer == null
1057
- ? result
1058
- : convertObjectKeys ( result , fieldNameNormalizer ) ,
1059
- )
1060
- . then ( result =>
1061
- findRestDirectivesThenInsertNullsForOmittedFields (
1062
- resultKey ,
1063
- result ,
1064
- mainDefinition ,
1065
- fragmentMap ,
1066
- mainDefinition . selectionSet ,
1067
- ) ,
1068
- )
1069
- . then ( result => addTypeNameToResult ( result , type , typePatcher ) ) ;
1070
- } catch ( error ) {
1071
- throw error ;
993
+ validateRequestMethodForOperationType ( method , operationType || 'query' ) ;
994
+
995
+ const requestParams = {
996
+ method,
997
+ headers : overrideHeaders || headers ,
998
+ body : body ,
999
+
1000
+ // Only set credentials if they're non-null as some browsers throw an exception:
1001
+ // https://github.com/apollographql/apollo-link-rest/issues/121#issuecomment-396049677
1002
+ ...( credentials ? { credentials } : { } ) ,
1003
+ } ;
1004
+ const requestUrl = `${ endpointOption . uri } ${ pathWithParams } ` ;
1005
+
1006
+ const response = await ( customFetch || fetch ) ( requestUrl , requestParams ) ;
1007
+ context . responses . push ( response ) ;
1008
+
1009
+ let result ;
1010
+ if ( response . ok ) {
1011
+ if (
1012
+ response . status === 204 ||
1013
+ response . headers . get ( 'Content-Length' ) === '0'
1014
+ ) {
1015
+ // HTTP-204 means "no-content", similarly Content-Length implies the same
1016
+ // This commonly occurs when you POST/PUT to the server, and it acknowledges
1017
+ // success, but doesn't return your Resource.
1018
+ result = { } ;
1019
+ } else {
1020
+ result = await response . json ( ) ;
1021
+ }
1022
+ } else if ( response . status === 404 ) {
1023
+ // In a GraphQL context a missing resource should be indicated by
1024
+ // a null value rather than throwing a network error
1025
+ result = null ;
1026
+ } else {
1027
+ // Default error handling:
1028
+ // Throw a JSError, that will be available under the
1029
+ // "Network error" category in apollo-link-error
1030
+ let parsed : any ;
1031
+ // responses need to be cloned as they can only be read once
1032
+ try {
1033
+ parsed = await response . clone ( ) . json ( ) ;
1034
+ } catch ( error ) {
1035
+ // its not json
1036
+ parsed = await response . clone ( ) . text ( ) ;
1037
+ }
1038
+ rethrowServerSideError (
1039
+ response ,
1040
+ parsed ,
1041
+ `Response not successful: Received status code ${ response . status } ` ,
1042
+ ) ;
1043
+ }
1044
+
1045
+ if ( endpointOption . responseTransformer ) {
1046
+ result = endpointOption . responseTransformer ( result , type ) ;
1047
+ } else if ( responseTransformer ) {
1048
+ result = responseTransformer ( result , type ) ;
1049
+ }
1050
+
1051
+ if ( fieldNameNormalizer !== null ) {
1052
+ result = convertObjectKeys ( result , fieldNameNormalizer ) ;
1072
1053
}
1054
+
1055
+ result = findRestDirectivesThenInsertNullsForOmittedFields (
1056
+ resultKey ,
1057
+ result ,
1058
+ mainDefinition ,
1059
+ fragmentMap ,
1060
+ mainDefinition . selectionSet ,
1061
+ ) ;
1062
+
1063
+ return addTypeNameToResult ( result , type , typePatcher ) ;
1073
1064
} ;
1074
1065
1075
1066
/**
@@ -1097,15 +1088,15 @@ const DEFAULT_JSON_SERIALIZER: RestLink.Serializer = (
1097
1088
* RestLink is an apollo-link for communicating with REST services using GraphQL on the client-side
1098
1089
*/
1099
1090
export class RestLink extends ApolloLink {
1100
- private endpoints : RestLink . Endpoints ;
1101
- private headers : Headers ;
1102
- private fieldNameNormalizer : RestLink . FieldNameNormalizer ;
1103
- private fieldNameDenormalizer : RestLink . FieldNameNormalizer ;
1104
- private typePatcher : RestLink . FunctionalTypePatcher ;
1105
- private credentials : RequestCredentials ;
1106
- private customFetch : RestLink . CustomFetch ;
1107
- private serializers : RestLink . Serializers ;
1108
- private responseTransformer : RestLink . ResponseTransformer ;
1091
+ private readonly endpoints : RestLink . Endpoints ;
1092
+ private readonly headers : Headers ;
1093
+ private readonly fieldNameNormalizer : RestLink . FieldNameNormalizer ;
1094
+ private readonly fieldNameDenormalizer : RestLink . FieldNameNormalizer ;
1095
+ private readonly typePatcher : RestLink . FunctionalTypePatcher ;
1096
+ private readonly credentials : RequestCredentials ;
1097
+ private readonly customFetch : RestLink . CustomFetch ;
1098
+ private readonly serializers : RestLink . Serializers ;
1099
+ private readonly responseTransformer : RestLink . ResponseTransformer ;
1109
1100
1110
1101
constructor ( {
1111
1102
uri,
0 commit comments