session
This page documents the session model.
Data Shape
Gadget's database stores session records by storing and retrieving each of the fields defined on the model in the Gadget Editor to a managed database. Gadget has generated a GraphQL type matching the configured fields for session:
1export type Session = {23 __typename: 'Session';45 /** The globally unique, unchanging identifier for this record. Assigned and managed by Gadget. */6 id: string;78 /** The time at which this record was first created. Set once upon record creation and never changed. Managed by Gadget. */9 createdAt: Date;1011 /** The time at which this record was last changed. Set each time the record is successfully acted upon by an action. Managed by Gadget. */12 updatedAt: Date;1314 /** The current state this record is in. Changed by invoking actions. Managed by Gadget. */15 state: (string | { [key: string]: Scalars['RecordState'] });1617 user: (User | null);1819 userId: string;2021 roles: Role[];2223 shopifySID: string;2425 /** Get all the fields for this record. Useful for not having to list out all the fields you want to retrieve, but slower. */26 _all: Record<string, any>;27};
1type Session {2 """3 The globally unique, unchanging identifier for this record. Assigned and managed by Gadget.4 """5 id: GadgetID67 """8 The time at which this record was first created. Set once upon record creation and never changed. Managed by Gadget.9 """10 createdAt: DateTime!1112 """13 The time at which this record was last changed. Set each time the record is successfully acted upon by an action. Managed by Gadget.14 """15 updatedAt: DateTime!1617 """18 The current state this record is in. Changed by invoking actions. Managed by Gadget.19 """20 state: RecordState!21 user: User22 userId: GadgetID23 roles: [Role!]24 shopifySID: String2526 """27 Get all the fields for this record. Useful for not having to list out all the fields you want to retrieve, but slower.28 """29 _all: JSONObject!30}
You can preview what a real record's shape looks like by fetching it using the example-app API playground.
Any fetched session record will have this same Session
type, and expose the same data by default, regardless of where it comes from. This means you can select any of the record's fields wherever you like in a GraphQL query according to the use case at hand.
session for Session Storage and Authentication
The session powers session functionality for the example-app app. Sessions store transient data specific to one browser interacting with the application, like whether a banner message has been shown, or anything else that needs to be specific to each session someone has with example-app.
example-app uses session to power user authentication using actions on session . Each user's current session is accessible using special GraphQL fields for querying and mutating. session are stored in the Gadget platform similarly to other models, but have this extra functionality for convenient access to the current session .
Because of this, session does not have normal findOne
, maybeFindOne
, findMany
, findFirst
, maybeFindFirst
, or create
actions. The Gadget platform manages the lifecycle of session records, and uses cookies to associate them with browser requests as needed.
session can still be managed like other models using the Internal API .
Retrieving the current session record
The current session record for a request can be retrieved using the currentSession
GraphQL field, or the .currentSession.get()
JS client function. You can also return only some fields, or extra fields beyond what Gadget retrieves by default, using the select
option.
The findOne
, maybeFindOne
, findMany
, findFirst
, and maybeFindFirst
record readers do not exist for session. If you need to change arbitrary records, or iterate the list of session, you can use the
Internal API
for session.
1const record = await api.currentSession.get();2// => a string3console.log(record.id);4// => a state value like { "created": "loggedOut" }5console.log(record.state);6// => a Date object7console.log(record.createdAt);
1const [result, refresh] = useGet(api.currentSession);2const { data, error, fetching } = result;3// => a string4console.log(result.data?.id)5// => a state value like { "created": "loggedOut" }6console.log(result.data?.state)7// => a Date object8console.log(result.data?.createdAt)
1query GetCurrentSession {2 currentSession {3 id4 createdAt5 }6}
{}
1const record = await api.currentSession.get();2// => a string3console.log(record.id);4// => a state value like { "created": "loggedOut" }5console.log(record.state);6// => a Date object7console.log(record.createdAt);
1const [result, refresh] = useGet(api.currentSession);2const { data, error, fetching } = result;3// => a string4console.log(result.data?.id)5// => a state value like { "created": "loggedOut" }6console.log(result.data?.state)7// => a Date object8console.log(result.data?.createdAt)
The current session is also available server-side within actions as part of the action context.
export const run: ActionRun = async ({ params, logger, api, session }) => {const { user } = session;// ...};
export const run: ActionRun = async ({ params, logger, api, session }) => {const { user } = session;// ...};
Invoking Actions
session records are changed by invoking Actions. Action are the things that "do" stuff -- creating data, deleting data, making API calls to other services, etc. Actions with a GraphQL API trigger each have one corresponding GraphQL mutation and a corresponding function available in the API client libraries.
Actions for session are executed on the currentSession
GraphQL field, or the .currentSession
JS client ModelManager
object. Each of these automatically refers to the session for the current browser session.
Action Result format
Each API action returns results in the same format that includes a success indicator, errors, and the actual result if the action succeeded. The result is the record that was acted on for a model action, or a list of records for a bulk action, or a JSON blob for Global Actions. Model actions that delete the record don't return the record.
The success
field returns a boolean indicating if the action executed as expected. Any execution errors are returned in the errors
object, which will always be null
if success
is true or contain ExecutionError
objects if success
is false.
ExecutionError
objects always have a message
describing what error prevented the action from succeeding, as well as a code
attribute that gives a stable, searchable, human-readable error class code for referencing this specific error. Details on each error code can be found in the Errors documentation. All ExecutionError
object types returned by the GraphQL object can be one of many types of error, where some types have extra data that is useful for remedying the error. All error types will always have message
and code
properties, but some, like InvalidRecordError
have extra fields for use by clients.
Errors when using the generated client
The generated JavaScript client automatically interprets errors from invoking actions and throws JavaScript Error
instances if the action didn't succeed. The Error
objects it throws are rich, and expose extra error properties beyond just message
and code
if they exist.
Errors thrown by the JavaScript client are easiest to catch by using a try/catch
statement around an await
, like so:
1import {2 GadgetOperationError,3 InvalidRecordError,4} from "@gadgetinc/api-client-core";56// must be in an async function to use await` syntax7export async function run({ api }) {8 try {9 return await api.exampleModel.create({ name: "example record name" });10 } catch (error) {11 if (error instanceof GadgetOperationError) {12 // a recognized general error has occurred, retry the operation or inspect \error.code\`13 console.error(error);14 } else if (error instanceof InvalidRecordError) {15 // the submitted input data for the action was invalid, inspect the invalid fields which \`InvalidRecordError\` exposes16 console.error(error.validationErrors);17 } else {18 // an unrecognized error occurred like an HTTP connection interrupted error or a syntax error. Re-throw it because it's not clear what to do to fix it19 throw error;20 }21 }22}
1import {2 GadgetOperationError,3 InvalidRecordError,4} from "@gadgetinc/api-client-core";56// must be in an async function to use await` syntax7export async function run({ api }) {8 try {9 return await api.exampleModel.create({ name: "example record name" });10 } catch (error) {11 if (error instanceof GadgetOperationError) {12 // a recognized general error has occurred, retry the operation or inspect \error.code\`13 console.error(error);14 } else if (error instanceof InvalidRecordError) {15 // the submitted input data for the action was invalid, inspect the invalid fields which \`InvalidRecordError\` exposes16 console.error(error.validationErrors);17 } else {18 // an unrecognized error occurred like an HTTP connection interrupted error or a syntax error. Re-throw it because it's not clear what to do to fix it19 throw error;20 }21 }22}
For more information on error codes, consult the Errors documentation.
session Log in via email
Input
Log in via email operates on the current session for the API client making a request. The Gadget platform manages which session is available, and no `id` parameter should be passed. The Log in via email action takes this input:
Example Invocation
const sessionRecord = await api.currentSession.logInViaEmail();
1const ExampleRunLogInViaEmailComponent = (props) => {2 const [{ data, error, fetching }, logInViaEmail] = useAction(3 api.currentSession.logInViaEmail4 );56 return (7 <>8 <button9 onClick={async () => {10 await logInViaEmail();11 }}12 >13 Run Action14 </button>15 Result: {JSON.stringify(data)}16 </>17 );18};
1mutation LogInViaEmail {2 currentSession {3 logInViaEmail {4 success5 errors {6 message7 ... on InvalidRecordError {8 validationErrors {9 apiIdentifier10 message11 }12 record13 model {14 apiIdentifier15 }16 }17 }18 session {19 __typename20 id21 state22 createdAt23 roles {24 key25 name26 }27 shopifySID28 updatedAt29 userId30 }31 }32 }33}
{}
Output
Log in via email returns data in the action result format, which includes the record if the action was successful. The fields returned for the record can be controlled with the select
option.
1export type LogInViaEmailSessionResult = {2 __typename: "LogInViaEmailSessionResult";34 success: Scalars["Boolean"];56 errors: ExecutionError[];78 actionRun: Scalars["String"] | null;910 session: Session | null;11};
1type LogInViaEmailSessionResult {2 success: Boolean!3 errors: [ExecutionError!]4 actionRun: String5 session: Session6}
1export type LogInViaEmailSessionResult = {2 __typename: "LogInViaEmailSessionResult";34 success: Scalars["Boolean"];56 errors: ExecutionError[];78 actionRun: Scalars["String"] | null;910 session: Session | null;11};
session Log out
Input
Log out operates on the current session for the API client making a request. The Gadget platform manages which session is available, and no `id` parameter should be passed. The Log out action takes this input:
Example Invocation
const sessionRecord = await api.currentSession.logOut();
1const ExampleRunLogOutComponent = (props) => {2 const [{ data, error, fetching }, logOut] = useAction(api.currentSession.logOut);34 return (5 <>6 <button7 onClick={async () => {8 await logOut();9 }}10 >11 Run Action12 </button>13 Result: {JSON.stringify(data)}14 </>15 );16};
1mutation LogOut {2 currentSession {3 logOut {4 success5 errors {6 message7 ... on InvalidRecordError {8 validationErrors {9 apiIdentifier10 message11 }12 record13 model {14 apiIdentifier15 }16 }17 }18 session {19 __typename20 id21 state22 createdAt23 roles {24 key25 name26 }27 shopifySID28 updatedAt29 userId30 }31 }32 }33}
{}
Output
Log out returns data in the action result format, which includes the record if the action was successful. The fields returned for the record can be controlled with the select
option.
1export type LogOutSessionResult = {2 __typename: "LogOutSessionResult";34 success: Scalars["Boolean"];56 errors: ExecutionError[];78 actionRun: Scalars["String"] | null;910 session: Session | null;11};
1type LogOutSessionResult {2 success: Boolean!3 errors: [ExecutionError!]4 actionRun: String5 session: Session6}
1export type LogOutSessionResult = {2 __typename: "LogOutSessionResult";34 success: Scalars["Boolean"];56 errors: ExecutionError[];78 actionRun: Scalars["String"] | null;910 session: Session | null;11};