Skip to main content

API Documentation

Multiforum uses GraphQL for its API. This guide covers how to explore and use the API.

GraphQL Playground​

Accessing the Playground​

When running the backend in development mode, the GraphQL Playground is available at:

http://localhost:4000/graphql

The playground provides:

  • Interactive query editor
  • Schema documentation
  • Query history
  • Response explorer

Setting Up Authentication​

For authenticated queries:

  1. Log in to the frontend
  2. Open browser dev tools → Application → Local Storage
  3. Copy the access token
  4. In Playground, click HTTP Headers:
{
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}

Query Examples​

Fetching Discussions​

query GetDiscussions($channelUniqueName: String!, $limit: Int, $offset: Int) {
getDiscussionsInChannel(
channelUniqueName: $channelUniqueName
limit: $limit
offset: $offset
) {
id
title
body
createdAt
Author {
username
profilePicURL
}
DiscussionChannels {
id
weightedVotesCount
Comments {
id
}
}
}
}

Variables:

{
"channelUniqueName": "general",
"limit": 10,
"offset": 0
}

Fetching Events​

query GetEvents($channelUniqueName: String!, $startDate: DateTime, $endDate: DateTime) {
events(
where: {
EventChannels_SOME: {
Channel: { uniqueName: $channelUniqueName }
}
startTime_GTE: $startDate
startTime_LTE: $endDate
}
) {
id
title
description
startTime
endTime
locationName
address
Poster {
username
}
}
}

Fetching a Single Discussion with Comments​

query GetDiscussionWithComments($discussionId: ID!, $channelUniqueName: String!) {
discussions(where: { id: $discussionId }) {
id
title
body
createdAt
Author {
username
profilePicURL
}
Tags {
text
}
}

getCommentSection(
discussionId: $discussionId
channelUniqueName: $channelUniqueName
) {
id
text
createdAt
CommentAuthor {
... on User {
username
profilePicURL
}
... on ModerationProfile {
displayName
}
}
ChildComments {
id
}
}
}

Fetching User Profile​

query GetUser($username: String!) {
users(where: { username: $username }) {
username
displayName
bio
profilePicURL
pronouns
location
createdAt
commentKarma
discussionKarma
}
}

Mutation Examples​

Creating a Discussion​

mutation CreateDiscussion($input: DiscussionCreateInputWithChannels!) {
createDiscussionWithChannelConnections(input: $input) {
id
title
body
createdAt
DiscussionChannels {
id
channelUniqueName
}
}
}

Variables:

{
"input": {
"discussionCreateInput": {
"title": "My New Discussion",
"body": "This is the content of my discussion."
},
"channelConnections": ["general"]
}
}

Creating a Comment​

mutation CreateComment($input: [CommentCreateInput!]!) {
createComments(input: $input) {
comments {
id
text
createdAt
}
}
}

Variables:

{
"input": [{
"text": "This is my comment",
"isRootComment": true,
"DiscussionChannel": {
"connect": {
"where": {
"node": {
"id": "discussion-channel-id"
}
}
}
}
}]
}

Creating an Event​

mutation CreateEvent($input: EventCreateInputWithChannels!) {
createEventWithChannelConnections(input: $input) {
id
title
startTime
endTime
EventChannels {
id
channelUniqueName
}
}
}

Upvoting a Discussion​

mutation UpvoteDiscussion($discussionChannelId: ID!) {
upvoteDiscussionChannel(discussionChannelId: $discussionChannelId) {
id
weightedVotesCount
}
}

Reporting Content​

mutation ReportDiscussion($discussionId: ID!, $channelUniqueName: String!, $reason: String!) {
reportDiscussion(
discussionId: $discussionId
channelUniqueName: $channelUniqueName
reason: $reason
) {
id
issueNumber
title
}
}

Schema Exploration​

Key Types​

TypeDescription
UserPlatform users
DiscussionForum discussions
DiscussionChannelDiscussion-channel join
EventEvents with dates/locations
EventChannelEvent-channel join
CommentComments on content
ChannelForum channels
IssueModeration issues
ServerConfigServer configuration

Permission-Controlled Mutations​

Many mutations require authentication and specific permissions:

MutationRequired Permission
createDiscussion...canCreateDiscussion
createEvent...canCreateEvent
createCommentscanCreateComment
archiveCommentcanHideComment
suspendUsercanSuspendUser

Introspection Query​

Get the full schema:

query IntrospectionQuery {
__schema {
types {
name
description
fields {
name
type {
name
}
}
}
}
}

Custom Queries​

Site-Wide Discussion List​

query GetSiteWideDiscussions($searchInput: String, $limit: Int, $offset: Int) {
getSiteWideDiscussionList(
searchInput: $searchInput
limit: $limit
offset: $offset
) {
id
title
body
createdAt
Author {
username
}
DiscussionChannels {
Channel {
uniqueName
displayName
}
}
}
}

User Contributions​

query GetUserContributions($username: String!, $limit: Int, $offset: Int) {
getUserContributions(
username: $username
limit: $limit
offset: $offset
) {
... on Discussion {
id
title
createdAt
}
... on Comment {
id
text
createdAt
}
... on Event {
id
title
startTime
}
}
}
query SearchChannels($searchInput: String) {
getSortedChannels(searchInput: $searchInput) {
uniqueName
displayName
description
channelIconURL
}
}

Error Handling​

GraphQL errors include:

  • UNAUTHENTICATED - Not logged in
  • FORBIDDEN - Insufficient permissions
  • NOT_FOUND - Resource doesn't exist
  • BAD_USER_INPUT - Invalid input data

Example error response:

{
"errors": [
{
"message": "You do not have permission to perform this action",
"extensions": {
"code": "FORBIDDEN"
}
}
]
}

Rate Limiting​

Currently, there's no rate limiting, but be considerate:

  • Batch related queries when possible
  • Use pagination for large data sets
  • Cache responses client-side

Frontend Integration​

Using Apollo Client​

import { useQuery, useMutation } from "@vue/apollo-composable";
import { GET_DISCUSSIONS } from "@/graphQLData/discussion/queries";

const { result, loading, error } = useQuery(GET_DISCUSSIONS, {
channelUniqueName: "general",
limit: 10,
});

const discussions = computed(() => result.value?.getDiscussionsInChannel ?? []);

Type Safety​

Import generated types:

import type { Discussion, Comment, User } from "@/__generated__/graphql";

Best Practices​

Query Optimization​

  • Request only needed fields
  • Use pagination for lists
  • Batch related queries

Caching​

Apollo Client caches by default:

  • Queries are cached
  • Mutations update the cache
  • Use cache policies appropriately

Error Handling​

Always handle errors:

const { error, onError } = useQuery(MY_QUERY);

onError((err) => {
console.error("Query failed:", err);
// Show user-friendly message
});