Use public fields in MJAPI
Using the @Public
Directive for Unauthenticated Access
@Public
Directive for Unauthenticated AccessThe @Public
directive in our system enables unauthenticated access to specific fields within our GraphQL schema. This feature is particularly useful for exposing public-facing data or allowing anonymous users to fetch certain information. In this article, we'll go through how to use the @Public
directive, provide code examples, and offer best practices to avoid common errors.
What is the @Public
Directive?
@Public
Directive?The @Public
directive is a GraphQL decorator that allows specific fields or operations to bypass authentication. By default, all fields in the system require authentication unless explicitly marked with the @Public
decorator. For complex object types, each child field also needs to be independently marked with @Public
to avoid authentication errors. This mechanism provides flexibility in building public endpoints for metadata or general information.
Using @Public
in Custom Resolvers
@Public
in Custom ResolversTo use the @Public
directive, you need to apply it to the relevant fields in your custom resolver. Below is an example of how to use @Public
with a custom ColorResolver
:
import { AppContext } from '../types.js';
import { Ctx, Field, Int, ObjectType, PubSub, PubSubEngine, Query, Resolver, Root, Subscription } from 'type-graphql';
import { Public } from '../directives/index.js';
@ObjectType()
export class Color {
@Field(() => Int)
@Public()
ID: number;
@Field(() => String)
@Public()
name: string;
@Field(() => String)
@Public()
createdZ: string;
}
@ObjectType()
export class ColorNotification {
@Public()
@Field(() => String, { nullable: true })
message?: string;
@Public()
@Field(() => Date)
date!: Date;
}
export interface ColorNotificationPayload {
message?: string;
}
@Resolver(Color)
export class ColorResolver {
@Subscription(() => ColorNotification, { topics: 'COLOR' })
@Public()
colorSubscription(@Root() { message }: ColorNotificationPayload): ColorNotification {
return { message, date: new Date() };
}
@Query(() => [Color])
@Public()
async colors(@Ctx() _ctx: AppContext, @PubSub() pubSub: PubSubEngine) {
const createdZ = new Date().toISOString();
pubSub.publish('COLOR', {
message: 'Colors were requested!',
});
return [
{ ID: 1, name: 'Red', createdZ },
{ ID: 2, name: 'Orange', createdZ },
{ ID: 3, name: 'Yellow', createdZ },
{ ID: 4, name: 'Green', createdZ },
{ ID: 5, name: 'Blue', createdZ },
{ ID: 6, name: 'Purple', createdZ },
];
}
}
Explanation
In this example:
- The
Color
andColorNotification
classes define GraphQL object types with fields marked by the@Public
decorator. This allows these fields (ID
,name
,createdZ
,message
, anddate
) to be accessed without requiring authentication. - The
ColorResolver
class contains two operations:colorSubscription
: A subscription to theCOLOR
topic that publishes messages and dates. It is marked with@Public()
, making it accessible to unauthenticated users.colors
: A query that returns a list of colors, marked with@Public()
, allowing public access to fetch this information.
By using the @Public()
decorator, you expose specific fields and operations without requiring the user to log in. However, it's crucial to ensure that every field and child field that you want to be publicly accessible has the @Public
decorator to avoid unexpected authentication errors.
Setting Up Custom Resolvers with @Public
@Public
When incorporating the @Public
directive into your custom resolvers, remember the following:
- Add the
@Public
Decorator: Apply the@Public
decorator to the fields, queries, or subscriptions that you want to be accessible without authentication. - Update the
[__mj].[Entity]
Table: Ensure that theCustomResolverAPI
value in the[__mj].[Entity]
table is set appropriately (e.g., set it to1
) to enable custom resolver functionality for the entity. - Mark Child Fields: For object types, mark each child field that should be publicly accessible with
@Public
.
Accessing @Public
Fields from an Angular App
@Public
Fields from an Angular AppOnce you’ve set up @Public
fields in your custom resolver, you can interact with them in your Angular app. Use the GraphQLDataProvider
's ExecuteGQL
method to run queries and mutations:
this.graphQLDataProvider.ExecuteGQL({
query: /* graphql */ `
query {
colors {
ID
name
createdZ
}
}
`,
});
In this example, the query fetches data from the colors
field, which is marked with the @Public
decorator in the ColorResolver
. This enables unauthenticated access to this data.
Common Errors and Best Practices
Unauthenticated Errors
If you encounter an "unauthenticated" error:
- Check that the
@Public
decorator is correctly applied to all fields you want to expose. - Ensure that nested fields (child fields) in object types also have the
@Public
directive if they should be accessible without authentication. - Remove the
Authorization
header when accessing public fields. If you include an invalid or expired token, the system will still attempt to authenticate and fail.
Manual API Clients
When using manual API clients (e.g., Postman), make sure to manually adjust headers to exclude Authorization
when interacting with @Public
fields.
Conclusion
The @Public
directive is a powerful tool for creating public-facing endpoints in your GraphQL schema. By marking fields, queries, and subscriptions with the @Public
decorator, you allow unauthenticated access while retaining the flexibility to restrict access to sensitive information. When using @Public
:
- Apply the directive to every field that should be accessible without authentication.
- Mark each child field in object types as necessary.
- Avoid setting the
Authorization
header if you don't have a valid token.
By following these guidelines, you can effectively use the @Public
directive to manage public access in your application.
Updated about 2 months ago