Skip to content

Commit

Permalink
(fix): support audiences on query parameters (#4067)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsinghvi authored Jul 19, 2024
1 parent 2e925a7 commit 91eeb1c
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { FernFileContext } from "../../FernFileContext";
import { AudienceId } from "../../filtered-ir/ids";
import { ExampleResolver } from "../../resolvers/ExampleResolver";
import { TypeResolver } from "../../resolvers/TypeResolver";
import { getPropertiesForAudience } from "../../utils/getPropertiesForAudience";
import { getPropertiesByAudience } from "../../utils/getPropertiesByAudience";
import { parseTypeName } from "../../utils/parseTypeName";
import { convertDeclaration } from "../convertDeclaration";
import { convertAliasTypeDeclaration } from "./convertAliasTypeDeclaration";
Expand Down Expand Up @@ -46,7 +46,7 @@ export async function convertTypeDeclaration({

let propertiesByAudience: Record<AudienceId, Set<string>> = {};
if (isRawObjectDefinition(typeDeclaration)) {
propertiesByAudience = getPropertiesForAudience(typeDeclaration.properties ?? {});
propertiesByAudience = getPropertiesByAudience(typeDeclaration.properties ?? {});
}

return {
Expand Down
32 changes: 23 additions & 9 deletions packages/cli/generation/ir-generator/src/filtered-ir/FilteredIr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@ export interface FilteredIr {
hasWebhook(webhook: Webhook): boolean;
hasWebhookPayloadProperty(webhookId: string, property: string): boolean;
hasRequestProperty(endpoint: string, property: string): boolean;
hasQueryParameter(endpoint: string, parameter: string): boolean;
hasSubpackageId(subpackageId: string): boolean;
}

export class FilteredIrImpl implements FilteredIr {
private types: Set<TypeId> = new Set();
private properties: Record<TypeId, Set<string>>;
private properties: Record<TypeId, Set<string> | undefined>;
private errors: Set<ErrorId> = new Set();
private services: Set<ServiceId> = new Set();
private endpoints: Set<EndpointId> = new Set();
private requestProperties: Record<EndpointId, Set<string>>;
private requestProperties: Record<EndpointId, Set<string> | undefined>;
private queryParameters: Record<EndpointId, Set<string> | undefined>;
private webhooks: Set<WebhookId> = new Set();
private webhookPayloadProperties: Record<WebhookId, Set<string>>;
private webhookPayloadProperties: Record<WebhookId, Set<string> | undefined>;
private subpackages: Set<SubpackageId> = new Set();

public constructor({
Expand All @@ -35,18 +37,20 @@ export class FilteredIrImpl implements FilteredIr {
endpoints,
webhooks,
subpackages,
queryParameters,
requestProperties,
webhookPayloadProperties,
properties
}: {
types: Set<TypeId>;
properties: Record<TypeId, Set<string>>;
properties: Record<TypeId, Set<string> | undefined>;
errors: Set<ErrorId>;
services: Set<ServiceId>;
requestProperties: Record<EndpointId, Set<string>>;
queryParameters: Record<EndpointId, Set<string> | undefined>;
requestProperties: Record<EndpointId, Set<string> | undefined>;
endpoints: Set<EndpointId>;
webhooks: Set<WebhookId>;
webhookPayloadProperties: Record<WebhookId, Set<string>>;
webhookPayloadProperties: Record<WebhookId, Set<string> | undefined>;
subpackages: Set<SubpackageId>;
}) {
this.types = types;
Expand All @@ -58,6 +62,7 @@ export class FilteredIrImpl implements FilteredIr {
this.webhookPayloadProperties = webhookPayloadProperties;
this.subpackages = subpackages;
this.requestProperties = requestProperties;
this.queryParameters = queryParameters;
}

public hasTypeId(typeId: string): boolean {
Expand All @@ -83,8 +88,8 @@ export class FilteredIrImpl implements FilteredIr {

public hasProperty(typeId: string, property: string): boolean {
const properties = this.properties[typeId];
// no properties were filtered for type
if (properties == null) {
// No audiences were configured.
return true;
}
return properties.has(property);
Expand All @@ -106,13 +111,22 @@ export class FilteredIrImpl implements FilteredIr {

public hasRequestProperty(endpoint: string, property: string): boolean {
const properties = this.requestProperties[endpoint];
// no properties were filtered for inlined request
if (properties == null) {
// No audiences were configured.
return true;
}
return properties.has(property);
}

public hasQueryParameter(endpoint: string, parameter: string): boolean {
const parameters = this.queryParameters[endpoint];
if (parameters == null) {
// No audiences were configured.
return true;
}
return parameters.has(parameter);
}

public hasSubpackage(subpackageId: string): boolean {
return this.subpackages.has(subpackageId);
}
Expand All @@ -126,8 +140,8 @@ export class FilteredIrImpl implements FilteredIr {

public hasWebhookPayloadProperty(webhookId: string, property: string): boolean {
const properties = this.webhookPayloadProperties[webhookId];
// no properties were filtered for inlined request
if (properties == null) {
// No audiences were configured.
return true;
}
return properties.has(property);
Expand Down
49 changes: 36 additions & 13 deletions packages/cli/generation/ir-generator/src/filtered-ir/IrGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { isInlineRequestBody, RawSchemas } from "@fern-api/yaml-schema";
import { isReferencedWebhookPayloadSchema } from "../converters/convertWebhookGroup";
import { FernFileContext } from "../FernFileContext";
import { IdGenerator } from "../IdGenerator";
import { getPropertiesForAudience } from "../utils/getPropertiesForAudience";
import { getPropertiesByAudience } from "../utils/getPropertiesByAudience";
import { FilteredIr, FilteredIrImpl } from "./FilteredIr";
import {
AudienceId,
Expand All @@ -28,6 +28,7 @@ import {
ErrorId,
ErrorNode,
InlinedRequestPropertiesNode,
InlinedRequestQueryParametersNode,
InlinedWebhookPayloadProperiesNode,
ServiceId,
SubpackageId,
Expand All @@ -41,6 +42,7 @@ import {
export class IrGraph {
private types: Record<TypeId, TypeNode> = {};
private properties: Record<TypeId, TypePropertiesNode> = {};
private queryParameters: Record<EndpointId, InlinedRequestQueryParametersNode> = {};
private requestProperties: Record<EndpointId, InlinedRequestPropertiesNode> = {};
private webhookProperties: Record<WebhookId, InlinedWebhookPayloadProperiesNode> = {};
private errors: Record<TypeId, ErrorNode> = {};
Expand Down Expand Up @@ -137,6 +139,14 @@ export class IrGraph {
for (const queryParameter of httpEndpoint.queryParameters) {
populateReferencesFromTypeReference(queryParameter.valueType, referencedTypes, referencedSubpackages);
}
if (rawEndpoint != null && rawEndpoint.request != null && typeof rawEndpoint.request !== "string") {
const parametersByAudience = getPropertiesByAudience(rawEndpoint.request["query-parameters"] ?? {});

this.queryParameters[endpointId] = {
endpointId,
parametersByAudience
};
}
if (httpEndpoint.requestBody != null) {
HttpRequestBody._visit(httpEndpoint.requestBody, {
inlinedRequestBody: (inlinedRequestBody) => {
Expand All @@ -152,9 +162,7 @@ export class IrGraph {
typeof rawEndpoint.request.body === "object" &&
isInlineRequestBody(rawEndpoint.request.body)
) {
const propertiesByAudience = getPropertiesForAudience(
rawEndpoint.request.body.properties ?? {}
);
const propertiesByAudience = getPropertiesByAudience(rawEndpoint.request.body.properties ?? {});
this.requestProperties[endpointId] = {
endpointId,
propertiesByAudience
Expand Down Expand Up @@ -289,7 +297,7 @@ export class IrGraph {
typeof rawWebhook.payload === "object" &&
!isReferencedWebhookPayloadSchema(rawWebhook.payload)
) {
const propertiesByAudience = getPropertiesForAudience(rawWebhook.payload.properties ?? {});
const propertiesByAudience = getPropertiesByAudience(rawWebhook.payload.properties ?? {});
this.webhookProperties[webhookId] = {
webhookId,
propertiesByAudience
Expand Down Expand Up @@ -347,9 +355,10 @@ export class IrGraph {
this.addReferencedTypes(typeIds, webhookNode.referencedTypes);
}

const properties: Record<TypeId, Set<string>> = {};
const requestProperties: Record<EndpointId, Set<string>> = {};
const webhookPayloadProperties: Record<WebhookId, Set<string>> = {};
const properties: Record<TypeId, Set<string> | undefined> = {};
const requestProperties: Record<EndpointId, Set<string> | undefined> = {};
const queryParameters: Record<EndpointId, Set<string> | undefined> = {};
const webhookPayloadProperties: Record<WebhookId, Set<string> | undefined> = {};

if (this.audiences.type === "filtered") {
for (const [typeId, typePropertiesNode] of Object.entries(this.properties)) {
Expand All @@ -368,6 +377,7 @@ export class IrGraph {
if (propertiesForTypeId.size > 0) {
properties[typeId] = propertiesForTypeId;
}
properties[typeId] = propertiesForTypeId.size > 0 ? propertiesForTypeId : undefined;
}

for (const [endpointId, requestPropertiesNode] of Object.entries(this.requestProperties)) {
Expand All @@ -383,9 +393,23 @@ export class IrGraph {
});
}
}
if (propertiesForEndpoint.size > 0) {
requestProperties[endpointId] = propertiesForEndpoint;
requestProperties[endpointId] = propertiesForEndpoint.size > 0 ? propertiesForEndpoint : undefined;
}

for (const [endpointId, queryParametersNode] of Object.entries(this.queryParameters)) {
if (!this.endpointsNeededForAudience.has(endpointId)) {
continue;
}
const parametersForEndpoint = new Set<string>();
for (const audience of this.audiences.audiences) {
const parametersByAudience = queryParametersNode.parametersByAudience[audience];
if (parametersByAudience != null) {
parametersByAudience.forEach((parameter) => {
parametersForEndpoint.add(parameter);
});
}
}
queryParameters[endpointId] = parametersForEndpoint.size > 0 ? parametersForEndpoint : undefined;
}

for (const [webhookId, webhookPaylodPropertiesNode] of Object.entries(this.webhookProperties)) {
Expand All @@ -401,9 +425,7 @@ export class IrGraph {
});
}
}
if (propertiesForWebhook.size > 0) {
requestProperties[webhookId] = propertiesForWebhook;
}
webhookPayloadProperties[webhookId] = propertiesForWebhook.size > 0 ? propertiesForWebhook : undefined;
}
}

Expand All @@ -412,6 +434,7 @@ export class IrGraph {
properties,
errors: errorIds,
requestProperties,
queryParameters,
services: this.servicesNeededForAudience,
endpoints: this.endpointsNeededForAudience,
webhooks: this.webhooksNeededForAudience,
Expand Down
12 changes: 12 additions & 0 deletions packages/cli/generation/ir-generator/src/filtered-ir/ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ export interface InlinedRequestPropertiesNode {
propertiesByAudience: Record<AudienceId, Set<string>>;
}

export interface InlinedRequestQueryParametersNode {
endpointId: EndpointId;
/* If audience not present, keep all properties */
parametersByAudience: Record<AudienceId, Set<string>>;
}

export interface InlinedRequestHeadersNode {
endpointId: EndpointId;
/* If audience not present, keep all properties */
parametersByAudience: Record<AudienceId, Set<string>>;
}

export interface InlinedWebhookPayloadProperiesNode {
webhookId: WebhookId;
/* If audience not present, keep all properties */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,11 @@ function filterIntermediateRepresentationForAudiences(
: undefined
};
});
if (httpEndpoint.queryParameters.length > 0) {
httpEndpoint.queryParameters = httpEndpoint.queryParameters.filter((queryParameter) => {
return filteredIr.hasQueryParameter(httpEndpoint.id, queryParameter.name.wireValue);
});
}
if (httpEndpoint.requestBody?.type === "inlinedRequestBody") {
return {
...httpEndpoint,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { RawSchemas } from "@fern-api/yaml-schema";
import { AudienceId } from "../filtered-ir/ids";

export function getPropertiesForAudience(
properties: Record<string, RawSchemas.ObjectPropertySchema>
export function getPropertiesByAudience(
properties: Record<string, RawSchemas.ObjectPropertySchema | RawSchemas.HttpQueryParameterSchema>
): Record<AudienceId, Set<string>> {
const propertiesByAudience: Record<AudienceId, Set<string>> = {};
for (const [property, propertyDeclaration] of Object.entries(properties)) {
Expand Down
1 change: 1 addition & 0 deletions test-definitions/fern/apis/audiences/definition/api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ name: audiences
display-name: Audiences API
audiences:
- public
- private
6 changes: 5 additions & 1 deletion test-definitions/fern/apis/audiences/definition/foo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ service:
find:
audiences:
- public
- private
path: ""
method: POST
request:
name: FindRequest
query-parameters:
optionalString: OptionalString
optionalString:
type: OptionalString
audiences:
- private
body:
properties:
publicProperty:
Expand Down

0 comments on commit 91eeb1c

Please sign in to comment.