Handle port-data-source errors in BackendTasks.

This commit is contained in:
Dillon Kearns 2023-01-02 11:02:22 -08:00
parent 4146ed1a11
commit a2a558992a
2 changed files with 152 additions and 25 deletions

View File

@ -75,20 +75,60 @@ function lookupOrPerform(portsFile, mode, rawRequest, hasFsAccess, useCache) {
if (!portBackendTask[portName]) {
if (portBackendTaskImportError === null) {
throw `BackendTask.Port.send "${portName}" was called, but I couldn't find a function with that name in the port definitions file. Is it exported correctly?`;
resolve({
kind: "response-json",
value: jsonResponse({
"elm-pages-internal-error": "PortNotDefined",
}),
});
} else if (portBackendTaskImportError === "missing") {
throw `BackendTask.Port.send "${portName}" was called, but I couldn't find the port definitions file. Be sure to create a 'port-data-source.ts' or 'port-data-source.js' file and maybe restart the dev server.`;
resolve({
kind: "response-json",
value: jsonResponse({
"elm-pages-internal-error": "MissingPortsFile",
}),
});
} else {
throw `BackendTask.Port.send "${portName}" was called, but I couldn't import the port definitions file, because of this exception: \`${portBackendTaskImportError}\` Are there syntax errors or expections thrown during import?`;
resolve({
kind: "response-json",
value: jsonResponse({
"elm-pages-internal-error": "ErrorInPortsFile",
error:
(portBackendTaskImportError &&
portBackendTaskImportError.stack) ||
"",
}),
});
}
} else if (typeof portBackendTask[portName] !== "function") {
throw `BackendTask.Port.send "${portName}" was called, but it is not a function. Be sure to export a function with that name from port-data-source.js`;
resolve({
kind: "response-json",
value: jsonResponse({
"elm-pages-internal-error": "ExportIsNotFunction",
error: typeof portBackendTask[portName],
}),
});
} else {
try {
const portFunctionResult = await portBackendTask[portName](input);
await fs.promises.writeFile(
responsePath,
JSON.stringify(jsonResponse(portFunctionResult))
);
resolve({
kind: "cache-response-path",
value: responsePath,
});
} catch (portCallError) {
resolve({
kind: "response-json",
value: jsonResponse({
"elm-pages-internal-error": "PortCallError",
error: portCallError,
}),
});
}
}
await fs.promises.writeFile(
responsePath,
JSON.stringify(jsonResponse(await portBackendTask[portName](input)))
);
resolve({ kind: "cache-response-path", value: responsePath });
} catch (error) {
console.trace(error);
reject({

View File

@ -15,7 +15,7 @@ import BackendTask
import BackendTask.Http
import BackendTask.Internal.Request
import Exception exposing (Catchable)
import Json.Decode exposing (Decoder)
import Json.Decode as Decode exposing (Decoder)
import Json.Encode as Encode
import TerminalText
@ -92,24 +92,111 @@ get portName input decoder =
]
|> BackendTask.Http.jsonBody
, expect =
decoder
Decode.oneOf
[ Decode.field "elm-pages-internal-error" Decode.string
|> Decode.andThen
(\errorKind ->
if errorKind == "PortNotDefined" then
Exception.Catchable (PortNotDefined { name = portName })
{ title = "Port Error"
, body =
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I expected to find a port named `"
, TerminalText.yellow portName
, TerminalText.text "` but I couldn't find it. Is the function exported in your port-data-source file?"
]
|> TerminalText.toString
}
|> Decode.succeed
else if errorKind == "ExportIsNotFunction" then
Decode.field "error" Decode.string
|> Decode.maybe
|> Decode.map (Maybe.withDefault "")
|> Decode.map
(\incorrectPortType ->
Exception.Catchable ExportIsNotFunction
{ title = "Port Error"
, body =
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I found an export called `"
, TerminalText.yellow portName
, TerminalText.text "` but I expected its type to be function, but instead its type was: "
, TerminalText.red incorrectPortType
]
|> TerminalText.toString
}
)
else if errorKind == "MissingPortsFile" then
Exception.Catchable MissingPortsFile
{ title = "Port Error"
, body =
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I couldn't find your port-data-source file. Be sure to create a 'port-data-source.ts' or 'port-data-source.js' file."
]
|> TerminalText.toString
}
|> Decode.succeed
else if errorKind == "ErrorInPortsFile" then
Decode.field "error" Decode.string
|> Decode.maybe
|> Decode.map (Maybe.withDefault "")
|> Decode.map
(\errorMessage ->
Exception.Catchable
ErrorInPortsFile
{ title = "Port Error"
, body =
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I couldn't import the port definitions file, because of this exception:\n\n"
, TerminalText.red errorMessage
, TerminalText.text "\n\nAre there syntax errors or exceptions thrown during import?"
]
|> TerminalText.toString
}
)
else if errorKind == "PortCallError" then
Decode.field "error" Decode.value
|> Decode.maybe
|> Decode.map (Maybe.withDefault Encode.null)
|> Decode.map
(\portCallError ->
Exception.Catchable
(PortCallError portCallError)
{ title = "Port Error"
, body =
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I couldn't import the port definitions file, because of this exception:\n\n"
, TerminalText.red (Encode.encode 2 portCallError)
, TerminalText.text "\n\nAre there syntax errors or exceptions thrown during import?"
]
|> TerminalText.toString
}
)
else
Exception.Catchable ErrorInPortsFile
{ title = "Port Error"
, body =
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I expected to find a port named `"
, TerminalText.yellow portName
, TerminalText.text "`."
]
|> TerminalText.toString
}
|> Decode.succeed
)
|> Decode.map Err
, decoder |> Decode.map Ok
]
|> BackendTask.Http.expectJson
}
|> BackendTask.onError
(\_ ->
BackendTask.fail
(Exception.Catchable Error
{ title = "Port Error"
, body =
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get."
]
|> TerminalText.toString
}
)
)
|> BackendTask.andThen BackendTask.fromResult
{-| -}
type Error
= -- TODO include additional context about error or better name to reflect the error state
Error
= Error
| ErrorInPortsFile
| MissingPortsFile
| PortNotDefined { name : String }
| PortCallError Decode.Value
| ExportIsNotFunction