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 (!portBackendTask[portName]) {
if (portBackendTaskImportError === null) { 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") { } 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 { } 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") { } 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) { } catch (error) {
console.trace(error); console.trace(error);
reject({ reject({

View File

@ -15,7 +15,7 @@ import BackendTask
import BackendTask.Http import BackendTask.Http
import BackendTask.Internal.Request import BackendTask.Internal.Request
import Exception exposing (Catchable) import Exception exposing (Catchable)
import Json.Decode exposing (Decoder) import Json.Decode as Decode exposing (Decoder)
import Json.Encode as Encode import Json.Encode as Encode
import TerminalText import TerminalText
@ -92,24 +92,111 @@ get portName input decoder =
] ]
|> BackendTask.Http.jsonBody |> BackendTask.Http.jsonBody
, expect = , 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.Http.expectJson
} }
|> BackendTask.onError |> BackendTask.andThen BackendTask.fromResult
(\_ ->
BackendTask.fail
(Exception.Catchable Error
{ title = "Port Error"
, body =
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get."
]
|> TerminalText.toString
}
)
)
{-| -} {-| -}
type Error 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