User
This page documents the User model.
Data Shape
Gadget's database stores User 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 User:
1export interface User {2 __typename: "User";34 /** The globally unique, unchanging identifier for this record. Assigned and managed by Gadget. */5 id: Scalars["GadgetID"];67 /** The time at which this record was first created. Set once upon record creation and never changed. Managed by Gadget. */8 createdAt: Scalars["DateTime"];910 /** The time at which this record was last changed. Set each time the record is successfully acted upon by an action. Managed by Gadget. */11 updatedAt: Scalars["DateTime"];1213 /** The current state this record is in. Changed by invoking actions. Managed by Gadget. */14 state: Scalars["RecordState"];1516 email: Scalars["EmailAddress"] | null;1718 roles: Role[];1920 sessions: SessionConnection;2122 /** Get all the fields for this record. Useful for not having to list out all the fields you want to retrieve, but slower. */23 _all: Scalars["JSONObject"];24}
1type User {2 """3 The globally unique, unchanging identifier for this record. Assigned and managed by Gadget.4 """5 id: GadgetID!67 """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 email: EmailAddress22 roles: [Role!]23 sessions(24 """25 Returns the items in the list that come after the specified cursor.26 """27 after: String2829 """30 Returns the first n items from the list.31 """32 first: Int3334 """35 Returns the items in the list that come before the specified cursor.36 """37 before: String3839 """40 Returns the last n items from the list.41 """42 last: Int43 ): SessionConnection!4445 """46 Get all the fields for this record. Useful for not having to list out all the fields you want to retrieve, but slower.47 """48 _all: JSONObject!49}
You can preview what a real record's shape looks like by fetching it using the Model Testing API Playground.
Any fetched User record will have this same User
type, and expose the same data by default, regardless of if it's fetched by ID or as part of a findMany
. 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.
Retrieving one User record
Individual User records can be retrieved using the "find by ID" API endpoint. You can also return only some fields, or
extra fields beyond what Gadget retrieves by default, using the select
option.
The findOne
function throws an error if no matching record is found, which you will need to catch and handle. Alternatively, you can use
the maybeFindOne
function, which returns null
if no record is found, without throwing an error.
Similarly, the useFindOne
React hook returns (but does not throw) an error when no matching record is found, while the useMaybeFindOne
hook simply returns null
if no record is found, without also returning an error.
const userRecord = await api.user.findOne("some-id");console.log(userRecord.id); //=> a stringconsole.log(userRecord.createdAt); //=> a Date object
const [result, refresh] = useFindOne(api.user, "some-id");const { data, error, fetching } = result;console.log(data?.id); //=> a stringconsole.log(data?.createdAt); //=> a Date object
1query GetOneUser($id: GadgetID!) {2 user(id: $id) {3 __typename4 id5 state6 createdAt7 email8 roles {9 key10 name11 }12 sessions {13 edges {14 node {15 id16 state17 createdAt18 roles {19 key20 name21 }22 updatedAt23 user {24 id25 state26 createdAt27 email28 roles {29 key30 name31 }32 updatedAt33 }34 }35 }36 }37 updatedAt38 }39}
{"id": "some-id"}
Retrieving the first of many User records
The first record from a list of records can be retrieved using the "find first" API endpoint. The source list of records can be filtered using the filter
option, sorted using the sort
option, searched using the search
option, though no pagination options are available on this endpoint. You can also return only some fields, or extra fields beyond what Gadget retrieves by default using the select
option.
The findFirst
function throws an error if no matching record is found, which you will need to catch and handle. Alternatively, you can use
the maybeFindFirst
function, which returns null
if no record is found, without throwing an error.
Similarly, the useFindFirst
React hook returns (but does not throw) an error when no matching record is found, while the useMaybeFindFirst
hook simply returns null
if no record is found, without also returning an error.
const userRecord = await api.user.findFirst();console.log(userRecord.id); //=> a stringconsole.log(userRecord.createdAt); //=> a Date object
const [result, refresh] = useFindFirst(api.user);const { data, error, fetching } = result;console.log(data?.id); //=> a stringconsole.log(data?.createdAt); //=> a Date object
1query FindManyUsers(2 $first: Int3 $search: String4 $sort: [UserSort!]5 $filter: [UserFilter!]6) {7 users(first: $first, search: $search, sort: $sort, filter: $filter) {8 edges {9 node {10 __typename11 id12 state13 createdAt14 email15 roles {16 key17 name18 }19 sessions {20 edges {21 node {22 id23 state24 createdAt25 roles {26 key27 name28 }29 updatedAt30 user {31 id32 state33 createdAt34 email35 roles {36 key37 name38 }39 updatedAt40 }41 }42 }43 }44 updatedAt45 }46 }47 }48}
{"first": 1}
Retrieving many User records
Pages of User records can be retrieved by using the "find many" API endpoint. The returned records can be filtered using the filter
option, sorted using the sort
option, searched using the search
option, and paginated using standard Relay-style pagination options. You can also return only some fields, or extra fields beyond what Gadget retrieves by default using the select
option.
This GraphQL endpoint returns records in the Relay Connection style (as a list of edge
s with node
s and cursor
s) so they can be paginated. The users
GraphQL endpoint works with any Relay-compatible caching client, or you can use Gadget's JS client for pagination with the findMany
function.
Find a page of Users
Fetch a page of records with the user.findMany
JS method or the users
GraphQL field. No options are required. The records returned will be implicitly sorted by ID ascending.
const userRecords = await api.user.findMany();console.log(userRecords.length); //=> a numberconsole.log(userRecords[0].id); //=> a string
const [result, refresh] = useFindMany(api.user);const { data, error, fetching } = result;console.log(data?.length); //=> a numberconsole.log(data?.[0].length); //=> a string
1query FindManyUsers {2 users {3 edges {4 node {5 __typename6 id7 state8 # ...9 createdAt10 updatedAt11 }12 }13 }14}
{}
Retrieving a single User record by a uniquely identifiable field
After adding a unique validation to a field, you can retrieve a single record by using the finders generated below. If you would like to edit the fields returned or filtering, see the filtering section.
Retrieving a single User record by ID
Individual User records can be retrieved using the "find many" API endpoint pre-filtered by the field's ID. Throws if stored data is not unique.
const userRecord = await api.user.findById("some-value");console.log(userRecord.id); //=> a string
const [result, refresh] = useFindBy(api.user.findById, "some-value");const { data, error, fetching } = result;console.log(data?.id); //=> a string
Retrieving a single User record by Email
Individual User records can be retrieved using the "find many" API endpoint pre-filtered by the field's Email. Throws if stored data is not unique.
const userRecord = await api.user.findByEmail("some-value");console.log(userRecord.id); //=> a string
const [result, refresh] = useFindBy(api.user.findByEmail, "some-value");const { data, error, fetching } = result;console.log(data?.id); //=> a string
Sorting
Records can be sorted in the database to retrieve them in a certain order. Records are always implicitly sorted by ID ascending unless an explicit filter on the id
field is defined. The GraphQL type UserSort
defines which fields can be sorted by.
Records can be sorted by multiple different fields and in multiple different directions by passing a list of UserSort
instead of just one.
1input UserSort {2 id: SortOrder3 createdAt: SortOrder4 updatedAt: SortOrder5 state: SortOrder6 email: SortOrder7}
Pass the sort
option to the JS client, or the sort
variable to a GraphQL query to sort the records returned.
const userRecords = await api.user.findMany({ sort: { createdAt: "Descending" } });
const [result, refresh] = useFindMany(api.user, {sort: { createdAt: "Descending" },});const { data, error, fetching } = result;
1query FindManyUsers($sort: [UserSort!]) {2 users(sort: $sort) {3 edges {4 node {5 __typename6 id7 state8 # ...9 createdAt10 updatedAt11 }12 }13 }14}
{"sort": {"createdAt": "Descending"}}
Sort by multiple fields by passing an array of { [field]: "Ascending" | "Descending" }
objects.
const userRecords = await api.user.findMany({sort: [{ state: "Descending" }, { createdAt: "Ascending" }],});
const [result, refresh] = useFindMany(api.user, {sort: [{ state: "Descending" }, { createdAt: "Ascending" }],});const { data, error, fetching } = result;
1query FindManyUsers($sort: [UserSort!]) {2 users(sort: $sort) {3 edges {4 node {5 __typename6 id7 state8 # ...9 createdAt10 updatedAt11 }12 }13 }14}
1{2 "sort": [3 {4 "state": "Descending"5 },6 {7 "createdAt": "Ascending"8 }9 ]10}
All primitive field types in Gadget are sortable so you are able to sort by fields you have added to a model as well.
const userRecords = await api.user.findMany({sort: { id: "Descending" },});
const [result, refresh] = useFindMany(api.user, {sort: { id: "Descending" },});const { data, error, fetching } = result;
1query FindManyUsers($sort: [UserSort!]) {2 users(sort: $sort) {3 edges {4 node {5 __typename6 id7 state8 # ...9 createdAt10 updatedAt11 }12 }13 }14}
{"sort": {"id": "Descending"}}
Searching
User records can be searched using Gadget's built in full text search functionality. Gadget search is appropriate for powering
autocompletes, searchable tables, or other experiences where humans are writing search queries. It's typo tolerant, synonym aware and supports
simple search operators like !
to exclude search terms.
Search Users by passing the search
parameter with a search query string.
Search isn't field specific in Gadget -- all String or RichText field types are searched with the built in search functionality.
const userRecords = await api.user.findMany({search: "a specific phrase to search for",});
const [result, refresh] = useFindMany(api.user, {search: "a specific phrase to search for",});const { data, error, fetching } = result;
1query FindManyUsers($search: String) {2 users(search: $search) {3 edges {4 node {5 __typename6 id7 state8 # ...9 createdAt10 updatedAt11 }12 }13 }14}
{"search": "a specific phrase to search for"}
Filtering
User records can be filtered to return only the appropriate records. Records can be filtered on any field, including those managed by Gadget or fields added by developers. Filters can be combined with sorts, searches and paginated using cursor based Relay pagination.
Filter Users by passing the filter
parameter with a filter object. Filter objects are nestable boolean conditions expressed as JS objects capturing a key, an operator, and usually a value.
The GraphQL type UserFilter
defines which fields can be filtered on.
Records can be filtered by multiple different fields. If you want to combine filters using boolean logic, nest them under the AND
, OR
, or NOT
keys of a parent filter. Filters can be nested deeply by passing multiple levels boolean condition filters.
You can also pass a list of filters to the filter
parameter which will be implicitly AND
ed with one another such that they all need to match for a record to be returned.
1input UserFilter {2 AND: [UserFilter]3 OR: [UserFilter]4 NOT: [UserFilter]5 id: IDFilter6 createdAt: DateTimeFilter7 updatedAt: DateTimeFilter8 state: StateFilter9 email: StringFilter10}
const yesterday = new Date(Date.now() - 864e5);const userRecords = await api.user.findMany({filter: { createdAt: { greaterThan: yesterday } },});
const yesterday = new Date(Date.now() - 864e5);const [result, refresh] = useFindMany(api.user, {filter: { createdAt: { greaterThan: yesterday } },});const { data, error, fetching } = result;
1query FindManyUsers($filter: [UserFilter!]) {2 users(filter: $filter) {3 edges {4 node {5 __typename6 id7 state8 # ...9 createdAt10 updatedAt11 }12 }13 }14}
1{2 "filter": {3 "createdAt": {4 "greaterThan": "2022-08-09T13:45:09.651Z"5 }6 }7}
1const yesterday = new Date(Date.now() - 86400000);2const oneWeekAgo = new Date(Date.now() - 604800000);3const userRecords = await api.user.findMany({4 filter: {5 OR: [6 {7 createdAt: { greaterThan: oneWeekAgo },8 },9 {10 updated: { greaterThan: yesterday },11 },12 ],13 },14});
1const yesterday = new Date(Date.now() - 86400000);2const oneWeekAgo = new Date(Date.now() - 604800000);3const [result, refresh] = useFindMany(api.user, {4 filter: {5 OR: [6 {7 createdAt: { greaterThan: oneWeekAgo },8 },9 {10 updated: { greaterThan: yesterday },11 },12 ],13 },14});15const { data, error, fetching } = result;
1query FindManyUsers($filter: [UserFilter!]) {2 users(filter: $filter) {3 edges {4 node {5 __typename6 id7 state8 # ...9 createdAt10 updatedAt11 }12 }13 }14}
1{2 "filter": {3 "OR": [4 {5 "createdAt": {6 "greaterThan": "2022-08-03T13:45:09.651Z"7 }8 },9 {10 "updated": {11 "greaterThan": "2022-08-09T13:45:09.651Z"12 }13 }14 ]15 }16}
Filter records that are in the created state
const userRecords = await api.user.findMany({filter: {state: { inState: "created" },},});
1const [result, refresh] = useFindMany(api.user, {2 filter: {3 state: { inState: "created" },4 },5});6const { data, error, fetching } = result;
1query FindManyUsers($filter: [UserFilter!]) {2 users(filter: $filter) {3 edges {4 node {5 __typename6 id7 state8 # ...9 createdAt10 updatedAt11 }12 }13 }14}
1{2 "filter": {3 "state": {4 "inState": "created"5 }6 }7}
Most field types in Gadget are filterable, so you are able to filter by fields you have added to a model as well.
const userRecords = await api.user.findMany({filter: {id: { isSet: true },},});
1const [result, refresh] = useFindMany(api.user, {2 filter: {3 id: { isSet: true },4 },5});6const { data, error, fetching } = result;
1query FindManyUsers($filter: [UserFilter!]) {2 users(filter: $filter) {3 edges {4 node {5 __typename6 id7 state8 # ...9 createdAt10 updatedAt11 }12 }13 }14}
1{2 "filter": {3 "id": {4 "isSet": true5 }6 }7}
Pagination
All Gadget record lists, including the top level User finder as well as associations to User, are structured as GraphQL connections. GraphQL connections are the defacto standard for querying lists and support cursor based forward and backward pagination. When querying via GraphQL, you must select the edges
field and then the node
field to get the User record. When querying using a Gadget API client, the GraphQL queries are generated for you and the records are unwrapped and returned as a GadgetRecordList
ready for use.
User pagination supports the standard GraphQL connection pagination arguments: first
+ after
, or last
+ before
. Pagination
is done using cursors, which you can retrieve from the edge.cursor
field or the pageInfo.startCursor
properties.
const userRecords = await api.user.findMany({ first: 25 });console.log(userRecords.length); //=> no greater than 25
const [result, refresh] = useFindMany(api.user, { first: 25 });const { data, error, fetching } = result;console.log(data?.length); //=> no greater than 25
1query FindManyUsers($first: Int, $after: String) {2 users(first: $first, after: $after) {3 edges {4 cursor5 node {6 __typename7 id8 state9 # ...10 createdAt11 updatedAt12 }13 }14 pageInfo {15 endCursor16 hasNextPage17 hasPreviousPage18 startCursor19 }20 }21}
{"first": 25}
The after
cursor used in this example data won't return any records if used in a real API request.
const userRecords = await api.user.findMany({ after: "abcdefg", first: 25 });
const [result, refresh] = useFindMany(api.user, { after: "abcdefg", first: 25 });const { data, error, fetching } = result;
1query FindManyUsers($first: Int, $after: String) {2 users(first: $first, after: $after) {3 edges {4 cursor5 node {6 __typename7 id8 state9 # ...10 createdAt11 updatedAt12 }13 }14 pageInfo {15 endCursor16 hasNextPage17 hasPreviousPage18 startCursor19 }20 }21}
{"first": 25,"after": "abcdefg"}
Pagination Limits
Root level record finders like users
support a maximum page size of 250 records, and a default page size of 50 records. The page size is controlled using the first
or last
GraphQL field arguments.
Related record finders that access lists of records through a HasMany or HasManyThrough field support a maximum page size of 100 records, and a default page size of 50 records.
Get the next or previous page
When using the generated JavaScript API client, the record lists returned from find many calls can be paginated using the nextPage()
or previousPage()
option.
Both nextPage()
and previousPage()
will throw an error if the corresponding hasNextPage
or hasPreviousPage
is false
.
1const userRecords =2 await api.user.findMany();3if (userRecords.hasNextPage) {4 const nextPage =5 await userRecords.nextPage();6}7if (userRecords.hasPreviousPage) {8 const prevPage =9 await userRecords.previousPage();10}
Selecting fields, and fields of fields
When using the JavaScript client, all of findOne
, maybeFindOne
, findMany
, findFirst
, maybeFindFirst
, and various action functions, allow requesting specific fields of a User and its relationships. The select
option controls which fields are selected in the generated GraphQL query sent to the Gadget API. Pass each field you want to select in an object, with true
as the value for scalar fields, and a nested object of the same shape for nested fields.
Gadget has a default selection that will retrieve all of the scalar fields for a User, as well as concise representations of each of the relationships containing an id
and an automatically inferred title field. If you don't pass a select
option to a record finder, this default selection will be used.
// fetch only the id, state, and createdAt fieldconst userRecords = await api.user.findMany({select: { id: true, state: true, createdAt: true },});
// fetch only the id, state, and createdAt fieldconst [result, refresh] = useFindMany(api.user, {select: { id: true, state: true, createdAt: true },});const { data, error, fetching } = result;
Type Safety
The select
option is fully type safe if you're using TypeScript. The returned GadgetRecord
type will have a <Shape>
exactly matching the fields and nested fields you selected. For more information, see Type Safety
.
This behavior of selecting only some fields is built right into GraphQL. If you want to limit or expand what you retrieve from a GraphQL query, include or exclude those fields in your GraphQL query. For more information on executing GraphQL queries, see GraphQL.
1// fetch the id, state, and createdAt field, and fetch some nested fields from an example relationship field named `someRelatedObject`2const userRecords = await api.user.findMany({3 select: {4 id: true,5 state: true,6 createdAt: true,7 someRelatedObject: { id: true, createdAt: true },8 },9});
1// fetch the id, state, and createdAt field, and fetch some nested fields from an example relationship field named `someRelatedObject`2const [result, refresh] = useFindMany(api.user, {3 select: {4 id: true,5 state: true,6 createdAt: true,7 someRelatedObject: { id: true, createdAt: true },8 },9});10const { data, error, fetching } = result;
Combining parameters
Sort, search, filtering, selection, and pagination parameters can be combined to access the exact set of records needed for your use case.
1const userRecords = await api.user.findMany({2 search: "<some search query>",3 sort: { createdAt: "Descending" },4 filter: { updatedAt: { greaterThan: new Date(Date.now() - 864e5) } },5 select: { id: true, createdAt: true },6 first: 25,7 after: "abcdefg",8});
1const [result, refresh] = useFindMany(api.user, {2 search: "<some search query>",3 sort: { createdAt: "Descending" },4 filter: { updatedAt: { greaterThan: new Date(Date.now() - 864e5) } },5 select: { id: true, createdAt: true },6 first: 25,7 after: "abcdefg",8});9const { data, error, fetching } = result;
1query FindManyUsers(2 $after: String3 $before: String4 $first: Int5 $last: Int6 $search: String7 $sort: [UserSort!]8 $filter: [UserFilter!]9) {10 users(11 after: $after12 before: $before13 first: $first14 last: $last15 search: $search16 sort: $sort17 filter: $filter18 ) {19 edges {20 cursor21 node {22 __typename23 id24 state25 createdAt26 email27 roles {28 key29 name30 }31 sessions {32 edges {33 node {34 id35 state36 createdAt37 roles {38 key39 name40 }41 updatedAt42 user {43 id44 state45 createdAt46 email47 roles {48 key49 name50 }51 updatedAt52 }53 }54 }55 }56 updatedAt57 }58 }59 pageInfo {60 endCursor61 hasNextPage62 hasPreviousPage63 startCursor64 }65 }66}
1{2 "search": "<some search query>",3 "sort": {4 "createdAt": "Descending"5 },6 "filter": {7 "updatedAt": {8 "greaterThan": "2022-08-09T13:45:09.849Z"9 }10 },11 "first": 25,12 "after": "abcdefg"13}
Invoking Actions
User records are changed by invoking Actions. Actions are the things that "do" stuff -- update records, make API calls, call backend code, etc. Actions each have one corresponding GraphQL mutation and a corresponding function available in the API client libraries. Nested Actions can also be invoked with the API client, by providing the actions as input to any relationship fields.
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 GadgetValidationError,4} from "@gadget-client/example-app";56// must be in an async function to use `await` syntax7const runAction = async () => {8 try {9 return await api.exampleModel.create(10 {11 exampleModel: {12 name: "example record name",13 },14 }15 );16 } catch (error) {17 if (18 error instanceof19 GadgetOperationError20 ) {21 // a recognized general error has occurred, retry the operation or inspect error.code`22 console.error(error);23 } else if (24 error instanceof25 GadgetValidationError26 ) {27 // the submitted input data for the action was invalid, inspect the invalid fields which `GadgetValidationError` exposes28 console.error(29 error.validationErrors30 );31 } else {32 // 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 ti33 throw error;34 }35 }36};
For more information on error codes, consult the Errors documentation.
User Create
The Create action transitions a User from Start
to Created
.
Input
Create accepts the following input parameters:
1export interface CreateUserInput {2 email?: (Scalars["String"] | null) | null;34 password?: (Scalars["String"] | null) | null;56 /** A string list of Gadget platform Role keys to assign to this record */7 roles?: (Scalars["String"] | null)[];89 sessions?: (SessionHasManyInput | null)[];10}1112export interface CreateUserArguments {13 user?: CreateUserInput | null;14}
1input CreateUserInput {2 email: String3 password: String45 """6 A string list of Gadget platform Role keys to assign to this record7 """8 roles: [String!]9 sessions: [SessionHasManyInput]10}1112input CreateUserArguments {13 user: CreateUserInput14}
1const userRecord = await api.user.create({2 user: {3 // field values for User4 },5});6console.log(userRecord.id); //=> a string
1const [result, createUser] = useAction(api.user.create);2const { data, error, fetching } = result;3await createUser({4 user: {5 // field values for User6 },7});8console.log(data?.id); //=> a string
1mutation ($user: CreateUserInput) {2 createUser(user: $user) {3 success4 errors {5 message6 ... on InvalidRecordError {7 validationErrors {8 apiIdentifier9 message10 }11 }12 }13 user {14 __typename15 id16 state17 createdAt18 email19 roles {20 key21 name22 }23 sessions {24 edges {25 node {26 id27 state28 createdAt29 roles {30 key31 name32 }33 updatedAt34 user {35 id36 state37 createdAt38 email39 roles {40 key41 name42 }43 updatedAt44 }45 }46 }47 }48 updatedAt49 }50 }51}
{"user": {}}
Output
Create returns the User. In the JS client, the fields returned can be controlled with the select
option. In GraphQL, the return format is the action result format, which includes the record if the action was successful. You can include or exclude the fields you need right in the mutation itself.
type CreateUserResult {success: Boolean!errors: [ExecutionError!]user: User}
User Delete
The Delete action destroys the record.
Input
Delete operates on one User in particular, identified by the id
variable.
await api.user.delete("some-id");
const [result, deleteUser] = useAction(api.user.delete);const { data, error, fetching } = result;await deleteUser({id: "some-id",});
1mutation ($id: GadgetID!) {2 deleteUser(id: $id) {3 success4 errors {5 message6 ... on InvalidRecordError {7 validationErrors {8 apiIdentifier9 message10 }11 }12 }13 }14}
{"id": "some-id"}
Output
Delete deletes the record, so it returns void
in the JS client. In GraphQL it returns only the success
and errors
from the action result format.
type DeleteUserResult {success: Boolean!errors: [ExecutionError!]}
User Update
The Update action transitions a User from Created
to Created
.
Input
Update operates on one User in particular, identified by the id
variable. Update accepts the following input parameters:
1export interface UpdateUserInput {2 email?: (Scalars["String"] | null) | null;34 password?: (Scalars["String"] | null) | null;56 /** A string list of Gadget platform Role keys to assign to this record */7 roles?: (Scalars["String"] | null)[];89 sessions?: (SessionHasManyInput | null)[];10}1112export interface UpdateUserArguments {13 user?: UpdateUserInput | null;14}
1input UpdateUserInput {2 email: String3 password: String45 """6 A string list of Gadget platform Role keys to assign to this record7 """8 roles: [String!]9 sessions: [SessionHasManyInput]10}1112input UpdateUserArguments {13 user: UpdateUserInput14}
1const userRecord = await api.user.update("some-id", {2 user: {3 // field values for User4 },5});6console.log(userRecord.id); //=> a string
1const [result, updateUser] = useAction(api.user.update);2const { data, error, fetching } = result;3await updateUser({4 id: "some-id",5 user: {6 // field values for User7 },8});9console.log(data?.id); //=> a string
1mutation ($id: GadgetID!, $user: UpdateUserInput) {2 updateUser(id: $id, user: $user) {3 success4 errors {5 message6 ... on InvalidRecordError {7 validationErrors {8 apiIdentifier9 message10 }11 }12 }13 user {14 __typename15 id16 state17 createdAt18 email19 roles {20 key21 name22 }23 sessions {24 edges {25 node {26 id27 state28 createdAt29 roles {30 key31 name32 }33 updatedAt34 user {35 id36 state37 createdAt38 email39 roles {40 key41 name42 }43 updatedAt44 }45 }46 }47 }48 updatedAt49 }50 }51}
{"id": "some-id","user": {}}
Output
Update returns the User. In the JS client, the fields returned can be controlled with the select
option. In GraphQL, the return format is the action result format, which includes the record if the action was successful. You can include or exclude the fields you need right in the mutation itself.
type UpdateUserResult {success: Boolean!errors: [ExecutionError!]user: User}
User Sign Up
The Sign Up action transitions a User from Start
to Created
.
Input
Sign Up accepts the following input parameters:
1export interface SignUpUserInput {2 email?: (Scalars["String"] | null) | null;34 password?: (Scalars["String"] | null) | null;56 /** A string list of Gadget platform Role keys to assign to this record */7 roles?: (Scalars["String"] | null)[];89 sessions?: (SessionHasManyInput | null)[];10}1112export interface SignUpUserArguments {13 user?: SignUpUserInput | null;14}
1input SignUpUserInput {2 email: String3 password: String45 """6 A string list of Gadget platform Role keys to assign to this record7 """8 roles: [String!]9 sessions: [SessionHasManyInput]10}1112input SignUpUserArguments {13 user: SignUpUserInput14}
1const userRecord = await api.user.signUp({2 user: {3 // field values for User4 },5});6console.log(userRecord.id); //=> a string
1const [result, signUpUser] = useAction(api.user.signUp);2const { data, error, fetching } = result;3await signUpUser({4 user: {5 // field values for User6 },7});8console.log(data?.id); //=> a string
1mutation ($user: SignUpUserInput) {2 signUpUser(user: $user) {3 success4 errors {5 message6 ... on InvalidRecordError {7 validationErrors {8 apiIdentifier9 message10 }11 }12 }13 user {14 __typename15 id16 state17 createdAt18 email19 roles {20 key21 name22 }23 sessions {24 edges {25 node {26 id27 state28 createdAt29 roles {30 key31 name32 }33 updatedAt34 user {35 id36 state37 createdAt38 email39 roles {40 key41 name42 }43 updatedAt44 }45 }46 }47 }48 updatedAt49 }50 }51}
{"user": {}}
Output
Sign Up returns the User. In the JS client, the fields returned can be controlled with the select
option. In GraphQL, the return format is the action result format, which includes the record if the action was successful. You can include or exclude the fields you need right in the mutation itself.
type SignUpUserResult {success: Boolean!errors: [ExecutionError!]user: User}
Bulk Actions
Actions that support it can be performed in bulk. Bulk Actions are executed as a single GraphQL mutation and have a corresponding function available in the API client libraries.
Bulk Actions are performed on a set of ids
. Bulk Actions repeat the same action, with the same options and parameters, across all ids
and should not be confused with batching
up different actions in the same request.
Bulk Actions will be performed on the entire set. If an action fails on an individual record, the Bulk Action will still occur on the other records in the set. Only the records which completed the action successfully will be returned.
Bulk User Delete
The Bulk Delete action destroys the records.
Input
Bulk Delete operates on a set of Users, identified by the ids
variable.
await api.user.bulkDelete(["some-id", "another-id"]);
const [userResult, bulkDelete] = useBulkAction(api.user.bulkDelete);const { data, error, fetching } = result;await bulkDelete({ ids: ["some-id", "another-id"] });
1mutation ($ids: [GadgetID!]!) {2 bulkDeleteUsers(ids: $ids) {3 success4 errors {5 message6 }7 }8}
1{2 "ids": [3 "some-id",4 "another-id"5 ]6}
Output
Bulk Delete deletes the record, so it returns void
in the JS client. In GraphQL it returns only the success
and errors
from the action result format.
type BulkDeleteUsersResult {success: Boolean!errors: [ExecutionError!]}