Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: auth service-to-service api #3148

Draft
wants to merge 10 commits into
base: 2893/multi-tenancy-v1
Choose a base branch
from

Conversation

BlairCurrey
Copy link
Contributor

@BlairCurrey BlairCurrey commented Dec 3, 2024

Changes proposed in this pull request

  • Adds a new ServiceAPIServer to auth
  • Adds new tenant CRUD routes to ServiceAPIServer
  • (WIP) Adds new authServiceAPIClient to backend that should be used by backend tenant service. The intention is to update that here when that PR gets merged in: feat(backend): tenants service (#3123) #3140

Context

fixes: #3125

Checklist

  • Related issues linked using fixes #number
  • Tests added/updated
  • Make sure that all checks pass
  • Bruno collection updated (if necessary)
  • Documentation issue created with user-docs label (if necessary)
  • OpenAPI specs updated (if necessary)

@github-actions github-actions bot added type: tests Testing related type: source Changes business logic pkg: auth Changes in the GNAP auth package. pkg: documentation Changes in the documentation package. labels Dec 3, 2024
@github-actions github-actions bot added the pkg: backend Changes in the backend package. label Dec 5, 2024
Comment on lines +28 to +69
private async request<T = any>(
path: string,
options: RequestInit
): Promise<T> {
const response = await fetch(`${this.baseUrl}${path}`, options)

if (!response.ok) {
let errorDetails
try {
errorDetails = await response.json()
} catch {
errorDetails = { message: response.statusText }
}

throw new AuthServiceClientError(
`Auth Service Client Error: ${response.status} ${response.statusText}`,
response.status,
errorDetails
)
}

if (
response.status === 204 ||
response.headers.get('Content-Length') === '0'
) {
return undefined as T
}

const contentType = response.headers.get('Content-Type')
if (contentType && contentType.includes('application/json')) {
try {
return (await response.json()) as T
} catch (error) {
throw new AuthServiceClientError(
`Failed to parse JSON response from ${path}`,
response.status
)
}
}

return (await response.text()) as T
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted to use the native fetch here although there were some behaviors I wasnt quite sure about. I tested with axios and mirrored how that works:

  1. not OK response (400, 500) etc. throws
  2. 204 returns undefined
  3. Success without body (200, 201, etc.) returns the response.text (just '' if not set)
  4. Interface accepts a generic which asserts the return type, although technically it could still return a string or undefined in the cases described above.

Comment on lines +74 to +83
async function createTenant(
deps: ServiceDependencies,
ctx: CreateContext
): Promise<void> {
const { body } = ctx.request

await deps.tenantService.create(body)

ctx.status = 204
}
Copy link
Contributor Author

@BlairCurrey BlairCurrey Dec 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mkurapov influenced by the pattern we've been talking about in the POC meetings. Not 201 with the resource returned. Originally I went with 201 but that really should have a body: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201

thus the 204 No Content for this and the update and delete.

Comment on lines +132 to +138
function toTenantResponse(tenant: Tenant): TenantResponse {
return {
id: tenant.id,
idpConsentUrl: tenant.idpConsentUrl,
idpSecret: tenant.idpSecret
}
}
Copy link
Contributor Author

@BlairCurrey BlairCurrey Dec 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to filter out the created, deleted, update timestamps basically. Figured we'd keep those in the return from the service layer and filter out here. Although I considered not returning them from the service since in theory maybe those are purely business logic concerns? Kinda academic at this point though.

Comment on lines +71 to +87
public tenant = {
get: (id: string) =>
this.request<Tenant>(`/tenant/${id}`, { method: 'GET' }),
create: (data: Omit<Tenant, 'id'>) =>
this.request('/tenant', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
}),
update: (id: string, data: Partial<Omit<Tenant, 'id'>>) =>
this.request(`/tenant/${id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
}),
delete: (id: string) => this.request(`/tenant/${id}`, { method: 'DELETE' })
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could probably move these methods and the Tenant interface out of this file if we want but opted to just put it here since it's really the only thing we need for the forseeable future.

}
}

export class AuthServiceClient {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost feels like this should be a different package outside of backend but this is the only consumer at this point so I felt like this keeps it simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intention is to add this as a dep to the tenant service, when thats merged in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg: auth Changes in the GNAP auth package. pkg: backend Changes in the backend package. pkg: documentation Changes in the documentation package. type: source Changes business logic type: tests Testing related
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant