Skip to content

Your First Query

Write your first GraphQL query with full type safety.

Write a Query

Write a GraphQL query directly in your component using the graphql function:

Template Literals

The graphql function requires template literals (backticks) for build-time type generation. Template literal interpolation (${...}) is not supported. Use GraphQL variables instead.

tsx
// src/components/UserProfile.tsx
import { 
graphql
} from 'mearie';
import {
useQuery
} from '@mearie/react';
interface UserProfileProps {
userId
: string;
} export const
UserProfile
= ({
userId
}: UserProfileProps) => {
const {
data
,
loading
,
error
} =
useQuery
(
graphql
(`
query GetUserQuery($id: ID!) { user(id: $id) { id name email avatar bio age } } `), {
id
:
userId
},
); if (
loading
) return <
div
>Loading...</
div
>;
if (
error
) return <
div
>Error: {
error
.
message
}</
div
>;
return ( <
div
>
<
img
src
={
data
.
user
.
avatar
}
alt
={
data
.
user
.
name
} />
<
h1
>{
data
.
user
.
name
}</
h1
>
{
data
.
user
.
bio
&& <
p
>{
data
.
user
.
bio
}</
p
>}
<
p
>
Email: {
data
.
user
.
email
}
</
p
>
<
p
>
Age: {
data
.
user
.
age
}
</
p
>
</
div
>
); };
vue
<!-- src/components/UserProfile.vue -->
<script setup lang="ts">
import { graphql } from 'mearie';
import { useQuery } from '@mearie/vue';

const props = defineProps<{ userId: string }>();

const { data, loading, error } = useQuery(
  graphql(`
    query GetUserQuery($id: ID!) {
      user(id: $id) {
        id
        name
        email
        avatar
        bio
        age
      }
    }
  `),
  () => ({ id: props.userId }),
);
</script>

<template>
  <div v-if="loading">Loading...</div>
  <div v-else-if="error">Error: {{ error.message }}</div>
  <div v-else>
    <img :src="data.user.avatar" :alt="data.user.name" />
    <h1>{{ data.user.name }}</h1>
    <p v-if="data.user.bio">{{ data.user.bio }}</p>
    <p>Email: {{ data.user.email }}</p>
    <p>Age: {{ data.user.age }}</p>
  </div>
</template>
svelte
<!-- src/components/UserProfile.svelte -->
<script lang="ts">
import { graphql } from 'mearie';
import { createQuery } from '@mearie/svelte';

interface Props {
  userId: string;
}

let { userId }: Props = $props();

const query = createQuery(
  graphql(`
    query GetUserQuery($id: ID!) {
      user(id: $id) {
        id
        name
        email
        avatar
        bio
        age
      }
    }
  `),
  () => ({ id: userId }),
);
</script>

{#if query.loading}
  <div>Loading...</div>
{:else if query.error}
  <div>Error: {query.error.message}</div>
{:else}
  <div>
    <img src={query.data.user.avatar} alt={query.data.user.name} />
    <h1>{query.data.user.name}</h1>
    {#if query.data.user.bio}
      <p>{query.data.user.bio}</p>
    {/if}
    <p>Email: {query.data.user.email}</p>
    <p>Age: {query.data.user.age}</p>
  </div>
{/if}
tsx
// src/components/UserProfile.tsx
import { type Component } from 'solid-js';
import { graphql } from 'mearie';
import { createQuery } from '@mearie/solid';

interface UserProfileProps {
  userId: string;
}

export const UserProfile: Component<UserProfileProps> = (props) => {
  const query = createQuery(
    graphql(`
      query GetUserQuery($id: ID!) {
        user(id: $id) {
          id
          name
          email
          avatar
          bio
          age
        }
      }
    `),
    () => ({ id: props.userId }),
  );

  if (query.loading) return <div>Loading...</div>;
  if (query.error) return <div>Error: {query.error.message}</div>;

  return (
    <div>
      <img src={query.data.user.avatar} alt={query.data.user.name} />
      <h1>{query.data.user.name}</h1>
      {query.data.user.bio && <p>{query.data.user.bio}</p>}
      <p>Email: {query.data.user.email}</p>
      <p>Age: {query.data.user.age}</p>
    </div>
  );
};

The build plugin automatically generates TypeScript types as you save. No separate type generation step needed.

Write a Mutation

Write a mutation directly in your component:

tsx
import { 
useState
} from 'react';
import {
graphql
} from 'mearie';
import {
useMutation
} from '@mearie/react';
interface EditUserFormProps {
userId
: string;
} export const
EditUserForm
= ({
userId
}: EditUserFormProps) => {
const [
name
,
setName
] =
useState
('');
const [
updateUser
, {
loading
}] =
useMutation
(
graphql
(`
mutation UpdateUserMutation($id: ID!, $name: String!) { updateUser(id: $id, input: { name: $name }) { id name } } `), ); const
handleSubmit
= async (
e
:
React
.
FormEvent
<HTMLFormElement>) => {
e
.
preventDefault
();
await
updateUser
({
id
:
userId
,
name
});
}; return ( <
form
onSubmit
={
handleSubmit
}>
<
input
value
={
name
}
onChange
={(
e
) =>
setName
(
e
.
target
.
value
)}
required
/>
<
button
type
="submit"
disabled
={
loading
}>
{
loading
? 'Saving...' : 'Save'}
</
button
>
</
form
>
); };
vue
<script setup lang="ts">
import { ref } from 'vue';
import { graphql } from 'mearie';
import { useMutation } from '@mearie/vue';

const props = defineProps<{ userId: string }>();
const name = ref('');

const { mutate, loading } = useMutation(
  graphql(`
    mutation UpdateUserMutation($id: ID!, $name: String!) {
      updateUser(id: $id, input: { name: $name }) {
        id
        name
      }
    }
  `),
);

const handleSubmit = async () => {
  await mutate({ id: props.userId, name: name.value });
};
</script>

<template>
  <form @submit.prevent="handleSubmit">
    <input v-model="name" required />
    <button :disabled="loading">{{ loading ? 'Saving...' : 'Save' }}</button>
  </form>
</template>
svelte
<script lang="ts">
import { graphql } from 'mearie';
import { createMutation } from '@mearie/svelte';

interface Props {
  userId: string;
}

let { userId }: Props = $props();
let name = $state('');

const mutation = createMutation(
  graphql(`
    mutation UpdateUserMutation($id: ID!, $name: String!) {
      updateUser(id: $id, input: { name: $name }) {
        id
        name
      }
    }
  `),
);

const handleSubmit = async (e: SubmitEvent) => {
  e.preventDefault();
  await mutation.mutate({ id: userId, name });
};
</script>

<form onsubmit={handleSubmit}>
  <input bind:value={name} required />
  <button type="submit" disabled={mutation.loading}>
    {mutation.loading ? 'Saving...' : 'Save'}
  </button>
</form>
tsx
import { type Component, createSignal } from 'solid-js';
import { graphql } from 'mearie';
import { createMutation } from '@mearie/solid';

interface EditUserFormProps {
  userId: string;
}

export const EditUserForm: Component<EditUserFormProps> = (props) => {
  const [name, setName] = createSignal('');
  const mutation = createMutation(
    graphql(`
      mutation UpdateUserMutation($id: ID!, $name: String!) {
        updateUser(id: $id, input: { name: $name }) {
          id
          name
        }
      }
    `),
  );

  const handleSubmit = async (e: SubmitEvent) => {
    e.preventDefault();
    await mutation.mutate({ id: props.userId, name: name() });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input value={name()} onInput={(e) => setName(e.currentTarget.value)} required />
      <button type="submit" disabled={mutation.loading}>
        {mutation.loading ? 'Saving...' : 'Save'}
      </button>
    </form>
  );
};

When the mutation completes, Mearie automatically updates the cache and re-renders affected components.

Next Steps