foomo-docs/assets/js/241a966b.62f942f6.js
2023-07-21 10:22:30 +00:00

1 line
7.5 KiB
JavaScript

"use strict";(self.webpackChunkfoomo=self.webpackChunkfoomo||[]).push([[5719],{3905:(r,e,t)=>{t.d(e,{Zo:()=>p,kt:()=>g});var n=t(7294);function o(r,e,t){return e in r?Object.defineProperty(r,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):r[e]=t,r}function a(r,e){var t=Object.keys(r);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(r);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(r,e).enumerable}))),t.push.apply(t,n)}return t}function s(r){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{};e%2?a(Object(t),!0).forEach((function(e){o(r,e,t[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(e){Object.defineProperty(r,e,Object.getOwnPropertyDescriptor(t,e))}))}return r}function i(r,e){if(null==r)return{};var t,n,o=function(r,e){if(null==r)return{};var t,n,o={},a=Object.keys(r);for(n=0;n<a.length;n++)t=a[n],e.indexOf(t)>=0||(o[t]=r[t]);return o}(r,e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(r);for(n=0;n<a.length;n++)t=a[n],e.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(r,t)&&(o[t]=r[t])}return o}var c=n.createContext({}),l=function(r){var e=n.useContext(c),t=e;return r&&(t="function"==typeof r?r(e):s(s({},e),r)),t},p=function(r){var e=l(r.components);return n.createElement(c.Provider,{value:e},r.children)},u="mdxType",d={inlineCode:"code",wrapper:function(r){var e=r.children;return n.createElement(n.Fragment,{},e)}},m=n.forwardRef((function(r,e){var t=r.components,o=r.mdxType,a=r.originalType,c=r.parentName,p=i(r,["components","mdxType","originalType","parentName"]),u=l(t),m=o,g=u["".concat(c,".").concat(m)]||u[m]||d[m]||a;return t?n.createElement(g,s(s({ref:e},p),{},{components:t})):n.createElement(g,s({ref:e},p))}));function g(r,e){var t=arguments,o=e&&e.mdxType;if("string"==typeof r||o){var a=t.length,s=new Array(a);s[0]=m;var i={};for(var c in e)hasOwnProperty.call(e,c)&&(i[c]=e[c]);i.originalType=r,i[u]="string"==typeof r?r:o,s[1]=i;for(var l=2;l<a;l++)s[l]=t[l];return n.createElement.apply(null,s)}return n.createElement.apply(null,t)}m.displayName="MDXCreateElement"},6738:(r,e,t)=>{t.r(e),t.d(e,{assets:()=>c,contentTitle:()=>s,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>l});var n=t(7462),o=(t(7294),t(3905));const a={},s="Errors",i={unversionedId:"projects/gotsrpc/service-interfaces/errors",id:"projects/gotsrpc/service-interfaces/errors",title:"Errors",description:"Handling errors is always hard and you have to differentiate about some capabilites between server-to-server and server-to-frontend communications:",source:"@site/docs/projects/gotsrpc/service-interfaces/errors.md",sourceDirName:"projects/gotsrpc/service-interfaces",slug:"/projects/gotsrpc/service-interfaces/errors",permalink:"/docs/projects/gotsrpc/service-interfaces/errors",draft:!1,editUrl:"https://github.com/foomo/foomo-docs/tree/main/foomo/docs/projects/gotsrpc/service-interfaces/errors.md",tags:[],version:"current",frontMatter:{},sidebar:"projectsSidebar",previous:{title:"Value Objects",permalink:"/docs/projects/gotsrpc/service-interfaces/value-objects"},next:{title:"TypeScript client transport",permalink:"/docs/projects/gotsrpc/client-transport"}},c={},l=[{value:"Server to Server",id:"server-to-server",level:2},{value:"Server to Frontend",id:"server-to-frontend",level:2},{value:"String Error Types",id:"string-error-types",level:3},{value:"Struct Error Types",id:"struct-error-types",level:3}],p={toc:l},u="wrapper";function d(r){let{components:e,...t}=r;return(0,o.kt)(u,(0,n.Z)({},p,t,{components:e,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"errors"},"Errors"),(0,o.kt)("p",null,"Handling errors is always hard and you have to differentiate about some capabilites between server-to-server and server-to-frontend communications:"),(0,o.kt)("h2",{id:"server-to-server"},"Server to Server"),(0,o.kt)("p",null,"When using server to server communication you can use the regular go ",(0,o.kt)("inlineCode",{parentName:"p"},"error")," interface.\nSince interfaces are not typed but still need to be able to checked on the client side, gotsrpc will wrap them during the encode phase to keep the information using ",(0,o.kt)("inlineCode",{parentName:"p"},"mapstructure"),"."),(0,o.kt)("p",null,"NOTE: Be aware though, that private attributes on structs will be lost during transportation"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-go"},'type CustomError struct {\n Message string\n data string // will be lost\n}\n\nfunc (e *CustomError) Error() string {\n return e.Message\n}\n\ntype Service interface {\n Do() (err error)\n}\n\nfunc main() {\n // ...\n err, clientErr := client.Do()\n if clientErr != nil {\n panic("client error") \n }\n \n // you will be able to use errors.Is() or errors.As()\n var customErr *CustomError\n if errors.As(err, &customErr) {\n // ... \n }\n if errors.Is(err, os.ErrExist) {\n // ...\n }\n}\n')),(0,o.kt)("h2",{id:"server-to-frontend"},"Server to Frontend"),(0,o.kt)("p",null,"On the frontend side, everything needs to be strictly typed so sth like this, does not transport well, since an interface implementation can not be marshalled."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-go"},"// from https://go.dev/blog/error-handling-and-go\ntype error interface {\n Error() string\n}\n")),(0,o.kt)("h3",{id:"string-error-types"},"String Error Types"),(0,o.kt)("p",null,"Scalar string error types provide a nice way to combine Go constants, that translate to TypeScript enums as errors:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-go",metastring:'title="Go"',title:'"Go"'},'type ScalarError string\n\nconst (\n ErrorFoo ScalarError = "foo"\n ErrorBar ScalarError = "bar"\n)\n\nfunc (e *ScalarError) Error() string {\n return string(*e)\n}\n\ntype Service interface {\n MightGoWrong() *ScalarError\n}\n')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript",metastring:'title="TypeScript"',title:'"TypeScript"'},'export enum ScalarError {\n ErrorBar = "bar",\n ErrorFoo = "foo",\n}\n\nexport interface ServiceClient {\n mightGoWrong(): Promise<ScalarError | null>;\n}\n')),(0,o.kt)("h3",{id:"struct-error-types"},"Struct Error Types"),(0,o.kt)("p",null,"If an enumeration is not enough and you want to add information to your errors a struct is a good choice (be careful not to expose secrets \ud83d\ude09) :"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"it can still implement the Error type"),(0,o.kt)("li",{parentName:"ul"},"it is still typed in contrast to other alternatives like maps")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-go",metastring:'title="Go"',title:'"Go"'},'type ErrorCode int\n\nconst (\n ErrorCodeFoo ErrorCode = 1\n ErrorCodeBar ErrorCode = 2\n)\n\ntype StructError struct {\n Message string `json:"message,omitempty"`\n Code ErrorCode `json:"errorCode"`\n}\n\nfunc (e *StructError) Error() string {\n return e.Message\n}\n\ntype Service struct {\n MightGoWrong() *StructError\n}\n')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript",metastring:'title="TypeScript"',title:'"TypeScript"'},"export enum ErrorCode {\n Bar = 2,\n Foo = 1,\n}\n\nexport interface StructError {\n message?:string;\n errorCode:ErrorCode;\n}\n\nexport interface ServiceClient {\n mightGoWrong(): Promise<StructError | null>;\n}\n")))}d.isMDXComponent=!0}}]);