Current section
Files
Jump to
Current section
Files
src/serverless_api.erl
%% @doc
%% AWS API Gateway integrations
-module(serverless_api).
-export([
return/1
]).
%%
%%
return({error, Reason}) ->
{Code, _} = Error = error_code(Reason),
serverless:error(#{
api => error,
reason => Reason,
status => Code
}),
return({Code, error_json(Error, Reason)});
return({Code, Json}) when is_map(Json) orelse is_list(Json) ->
return({Code, jsx:encode(Json)});
return({Code, Text}) when is_binary(Text) ->
{ok,
#{
statusCode => return_code(Code),
body => Text,
headers => default_cors()
}
};
return({Code, Head, Json}) when is_map(Json) orelse is_list(Json) ->
return({Code, Head, jsx:encode(Json)});
return({Code, Head, Text}) when is_binary(Text) ->
{ok,
#{
statusCode => return_code(Code),
body => Text,
headers => maps:merge(Head, default_cors())
}
}.
return_code({Code, _}) ->
Code;
return_code(Code) when is_tuple(Code) ->
erlang:element(1, status_code(erlang:element(1, Code)));
return_code(Code) ->
erlang:element(1, status_code(Code)).
%%
%%
error_code({Reason, _}) ->
status_code(Reason);
error_code(Code) when is_tuple(Code) ->
status_code(erlang:element(1, Code));
error_code(Reason) ->
status_code(Reason).
error_json({Code, Text}, Reason) ->
#{
type => filename:join([<<"https://httpstatuses.com">>, typecast:s(Code)]),
status => Code,
title => Text,
details => error_reason(Reason)
}.
error_reason({_, #{} = Reason}) ->
Reason;
error_reason({Reason, Details}) ->
typecast:s([typecast:s(Reason), $:, $ , typecast:s(Details)]);
error_reason(#{} = Reason) ->
Reason;
error_reason(Reason) ->
typecast:s(Reason).
%%
%%
default_cors() ->
#{
<<"Access-Control-Allow-Origin">> => <<"*">>,
<<"Access-Control-Allow-Methods">> => <<"GET, PUT, POST, DELETE, OPTIONS">>,
<<"Access-Control-Allow-Headers">> => <<"Content-Type, Authorization, Accept">>,
<<"Access-Control-Max-Age">> => 600
}.
%%
%%
status_code(100) -> {100, <<"Continue">>};
status_code(101) -> {101, <<"Switching Protocols">>};
status_code(200) -> {200, <<"OK">>};
status_code(201) -> {201, <<"Created">>};
status_code(202) -> {202, <<"Accepted">>};
status_code(203) -> {203, <<"Non-Authoritative Information">>};
status_code(204) -> {204, <<"No Content">>};
status_code(205) -> {205, <<"Reset Content">>};
status_code(206) -> {206, <<"Partial Content">>};
status_code(300) -> {300, <<"Multiple Choices">>};
status_code(301) -> {301, <<"Moved Permanently">>};
status_code(302) -> {302, <<"Found">>};
status_code(303) -> {303, <<"See Other">>};
status_code(304) -> {304, <<"Not Modified">>};
status_code(307) -> {307, <<"Temporary Redirect">>};
status_code(400) -> {400, <<"Bad Request">>};
status_code(401) -> {401, <<"Unauthorized">>};
status_code(402) -> {402, <<"Payment Required">>};
status_code(403) -> {403, <<"Forbidden">>};
status_code(404) -> {404, <<"Not Found">>};
status_code(405) -> {405, <<"Method Not Allowed">>};
status_code(406) -> {406, <<"Not Acceptable">>};
status_code(407) -> {407, <<"Proxy Authentication Required">>};
status_code(408) -> {408, <<"Request Timeout">>};
status_code(409) -> {409, <<"Conflict">>};
status_code(410) -> {410, <<"Gone">>};
status_code(411) -> {411, <<"Length Required">>};
status_code(412) -> {412, <<"Precondition Failed">>};
status_code(413) -> {413, <<"Request Entity Too Large">>};
status_code(414) -> {414, <<"Request-URI Too Long">>};
status_code(415) -> {415, <<"Unsupported Media Type">>};
status_code(416) -> {416, <<"Requested Range Not Satisfiable">>};
status_code(417) -> {417, <<"Expectation Failed">>};
status_code(422) -> {422, <<"Unprocessable Entity">>};
status_code(500) -> {500, <<"Internal Server Error">>};
status_code(501) -> {501, <<"Not Implemented">>};
status_code(502) -> {502, <<"Bad Gateway">>};
status_code(503) -> {503, <<"Service Unavailable">>};
status_code(504) -> {504, <<"Gateway Timeout">>};
status_code(505) -> {505, <<"HTTP Version Not Supported">>};
%status_code(100) -> <<"100 Continue">>;
%status_code(101) -> <<"101 Switching Protocols">>;
status_code(ok) -> status_code(200);
status_code(created) -> status_code(201);
status_code(accepted) -> status_code(202);
%status(203) -> <<"203 Non-Authoritative Information">>;
status_code(no_content) -> status_code(204);
%status(205) -> <<"205 Reset Content">>;
%status(206) -> <<"206 Partial Content">>;
%status(300) -> <<"300 Multiple Choices">>;
%status(301) -> <<"301 Moved Permanently">>;
status_code(redirect) -> status_code(302);
%status(303) -> <<"303 See Other">>;
%status(304) -> <<"304 Not Modified">>;
%status(307) -> <<"307 Temporary Redirect">>;
status_code(badarg) -> status_code(400);
status_code(unauthorized) -> status_code(401);
status_code(expired) -> status_code(401);
%status(402) -> <<"402 Payment Required">>;
status_code(forbidden) -> status_code(403);
status_code(not_found) -> status_code(404);
status_code(enoent) -> status_code(404);
status_code(not_allowed) -> status_code(405);
status_code(not_acceptable) -> status_code(406);
%status(407) -> <<"407 Proxy Authentication Required">>;
%status(408) -> <<"408 Request Timeout">>;
status_code(conflict) -> status_code(409);
status_code(duplicate)-> status_code(409);
%status(410) -> <<"410 Gone">>;
%status(411) -> <<"411 Length Required">>;
%status(412) -> <<"412 Precondition Failed">>;
%status(413) -> <<"413 Request Entity Too Large">>;
%status(414) -> <<"414 Request-URI Too Long">>;
status_code(bad_mime_type) -> status_code(415);
%status(416) -> <<"416 Requested Range Not Satisfiable">>;
%status(417) -> <<"417 Expectation Failed">>;
%status(422) -> <<"422 Unprocessable Entity">>;
status_code(required) -> status_code(500);
status_code(not_implemented) -> status_code(501);
%status(502) -> <<"502 Bad Gateway">>;
status_code(not_available) -> status_code(503);
%status(504) -> <<"504 Gateway Timeout">>;
%status(505) -> <<"505 HTTP Version Not Supported">>.
status_code(Code) when is_atom(Code) -> status_code(500);
status_code(Code) when is_integer(Code) -> status_code(Code).