Skip to content

Commit

Permalink
feat(api): refact implementation (#223)
Browse files Browse the repository at this point in the history
* user token start

* tests

* refactor auth

* caching

* api

* fix test

* comment

* expiry

* batching

* remove user token implementation

* Revert "remove user token implementation"

This reverts commit 1e1dd78.

* refact auth

* remove file

* fix

* refact client auth function

* refact function

* refact

* fix

* remove file

* end turn route

* responses

* return message also

* use cache for collectors

* hintRespondingTo

* incomingId

* bump messaging client

* turn id

* collect flag

* fix ui

* backend validate user token is correct

* schema

* socket auth

* update testing ui

* bring changes

* remove user token api

* remove user token api

* revert

* remove correct user token api

* bring changes

* extract constant

* verifyToken

* fix tests

* users.get

* socket prevent lost requests

* conversations socket

* some refact and changes

* refact schema validation

* refact user rights check

* remove nonsense

* socket refact

* move socket code at of api start

* socket root class

* remove private

* refact schema

* fix

* fix

* dont server client

* move api routes to functions

* different collect route

* better api route names

* refact schema validation

* refact messages

* refact conversations

* refact users

* remove ui from changes

* update ui

* custom timeout

* fix

* better socket

* better socket

* bring changes

* fix

* fix

* tests start

* fix

* more tests

* tests

* pr comments

* fix

* fix

* comments

* fixes and tests

* adjust api.rest

* better tests

* fix delete message

* remove next parameter

* pr comments

* fix

* add todo

* update doc

* return 404

* delete 204

* client error handling + user endpoint return 404

* remove error handling for list calls

* fix sync disable

* chore(client): v0.0.9

Co-authored-by: Laurent Leclerc-Poulin <laurentleclercpoulin@gmail.com>
  • Loading branch information
samuelmasse and laurentlp authored Nov 5, 2021
1 parent 42a1d5b commit c8aa881
Show file tree
Hide file tree
Showing 22 changed files with 596 additions and 381 deletions.
22 changes: 19 additions & 3 deletions api.rest
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// @baseUrl = https://messaging.botpress.dev/
@clientId = YOUR_CLIENT_ID
@clientToken = YOUR_TOKEN
@channel= YOUR_CHANNEL
@userId = YOUR_USER_ID
@convoId = YOUR_CONVO_ID

### Auth messaging cloud
Expand Down Expand Up @@ -54,7 +54,7 @@ x-bp-messaging-client-token: {{clientToken}}
Content-Type: application/json

{
"userId": "my-user-id"
"userId": "{{userId}}"
}

### Send Text
Expand All @@ -65,14 +65,30 @@ x-bp-messaging-client-token: {{clientToken}}
Content-Type: application/json

{
"collect": false,
"conversationId": "{{convoId}}",
"authorId": null,
"payload": {
"type": "text",
"text": "Hello this is a text message!"
}
}

### Converse
POST {{baseUrl}}/api/messages/collect
Authorization: Bearer {{authToken}}
x-bp-messaging-client-id: {{clientId}}
x-bp-messaging-client-token: {{clientToken}}
Content-Type: application/json

{
"conversationId": "{{convoId}}",
"authorId": "{{userId}}",
"payload": {
"type": "text",
"text": "Hello this is a converse message!"
}
}

### Send Image
POST {{baseUrl}}/api/messages
Authorization: Bearer {{authToken}}
Expand Down
43 changes: 26 additions & 17 deletions doc/routes.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,6 @@ x-bp-messaging-client-token: `clientToken`

Provides information on configured channels

## Chat

POST `/api/chat/reply/`

x-bp-messaging-client-id: `clientId`

x-bp-messaging-client-token: `clientToken`

- `channel`: Channel to send the message to
- `conversationId`: Id of conversation to send the message to
- `payload`: Content of the message to send (ex: `{ "type": "text", "text": "Hello!" }`)

## Users

POST `/api/users`
Expand Down Expand Up @@ -134,15 +122,15 @@ x-bp-messaging-client-token: `clientToken`

Gets a conversation by id

GET `/api/conversations?userId=&limit=`
GET `/api/conversations/user/:userId?limit=`

x-bp-messaging-client-id: `clientId`

x-bp-messaging-client-token: `clientToken`

Lists the conversations of a user

GET `/api/conversations/:userId/recent`
GET `/api/conversations/user/:userId/recent`

x-bp-messaging-client-id: `clientId`

Expand All @@ -164,6 +152,19 @@ x-bp-messaging-client-token: `clientToken`

Creates a new message

POST `/api/messages/collect`

x-bp-messaging-client-id: `clientId`

x-bp-messaging-client-token: `clientToken`

- `conversationId`: Id of the conversation
- `authorId`: Id of the writer of the message
- `payload`: Content of the message
- `timeout`: Optional. Timeout for the message collection (max 50s)

Creates a new message and collects responses

GET `/api/messages/:id`

x-bp-messaging-client-id: `clientId`
Expand All @@ -172,18 +173,26 @@ x-bp-messaging-client-token: `clientToken`

Gets a message by id

GET `/api/messages?conversationId=&limit=`
DELETE `/api/messages/:id`

x-bp-messaging-client-id: `clientId`

x-bp-messaging-client-token: `clientToken`

Deletes a message by id

GET `/api/messages/conversation/:conversationId?limit=`

x-bp-messaging-client-id: `clientId`

x-bp-messaging-client-token: `clientToken`

List messages of a conversation

DELETE `/api/messages?id=&conversationId=`
DELETE `/api/messages/conversation/:conversationId`

x-bp-messaging-client-id: `clientId`

x-bp-messaging-client-token: `clientToken`

Deletes messages. Can filter by id or by conversation id.
Deletes all messages of a conversation
19 changes: 19 additions & 0 deletions packages/client/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Config } from '@jest/types'
import { defaults as tsjPreset } from 'ts-jest/presets'

const config: Config.InitialOptions = {
preset: 'ts-jest',
projects: [
{
testMatch: ['<rootDir>/test/**/(*.)test.ts'],
displayName: { name: 'Client', color: 'blue' },
testEnvironment: 'node',
transform: {
...tsjPreset.transform
},
clearMocks: true
}
]
}

export default config
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@botpress/messaging-client",
"version": "0.0.8",
"version": "0.0.9",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"source": "src/index.ts",
Expand Down
6 changes: 3 additions & 3 deletions packages/client/src/conversations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ export class ConversationClient extends BaseClient {
}, undefined)
}

async list(userId: string, limit: number): Promise<ConversationWithLastMessage[]> {
return (await this.http.get<Conversation[]>('/conversations', { params: { userId, limit } })).data.map((x) =>
async list(userId: string, limit?: number): Promise<ConversationWithLastMessage[]> {
return (await this.http.get<Conversation[]>(`/conversations/user/${userId}`, { params: { limit } })).data.map((x) =>
this.deserialize(x)
)
}

async getRecent(userId: string): Promise<Conversation> {
return this.deserialize((await this.http.get<Conversation>(`/conversations/${userId}/recent`)).data)
return this.deserialize((await this.http.get<Conversation>(`/conversations/user/${userId}/recent`)).data)
}

public deserialize(conversation: Conversation): Conversation {
Expand Down
35 changes: 21 additions & 14 deletions packages/client/src/messages.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,46 @@
import { Message } from '@botpress/messaging-base'
import { Message, uuid } from '@botpress/messaging-base'
import { BaseClient } from './base'
import { handleNotFound } from './errors'

export class MessageClient extends BaseClient {
async create(
conversationId: string,
authorId: string | undefined,
conversationId: uuid,
authorId: uuid | undefined,
payload: any,
flags?: { incomingId: string }
flags?: { incomingId: uuid }
): Promise<Message> {
return this.deserialize(
(await this.http.post<Message>('/messages', { conversationId, authorId, payload, incomingId: flags?.incomingId }))
.data
)
}

async get(id: string): Promise<Message | undefined> {
async get(id: uuid): Promise<Message | undefined> {
return handleNotFound(async () => {
this.deserialize((await this.http.get<Message>(`/messages/${id}`)).data)
return this.deserialize((await this.http.get<Message>(`/messages/${id}`)).data)
}, undefined)
}

async list(conversationId: string, limit: number): Promise<Message[]> {
async list(conversationId: uuid, limit?: number): Promise<Message[]> {
return (await this.http.get<Message[]>(`/messages/conversation/${conversationId}`, { params: { limit } })).data.map(
(x) => this.deserialize(x)
)
}

async delete(id: uuid): Promise<boolean> {
return handleNotFound(async () => {
return (await this.http.get<Message[]>('/messages', { params: { conversationId, limit } })).data.map((x) =>
this.deserialize(x)
)
}, [])
await this.http.delete<boolean>(`/messages/${id}`)
return true
}, false)
}

async delete(filters: { id?: string; conversationId?: string }): Promise<number> {
return (await this.http.delete<{ count: number }>('/messages', { params: filters })).data.count
async deleteByConversation(conversationId: uuid): Promise<number> {
return handleNotFound(async () => {
return (await this.http.delete<{ count: number }>(`/messages/conversation/${conversationId}`)).data.count
}, 0)
}

async endTurn(id: string) {
async endTurn(id: uuid) {
await this.http.post(`/messages/turn/${id}`)
}

Expand Down
108 changes: 108 additions & 0 deletions packages/client/test/client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { Conversation, Message, MessagingClient, User, uuid } from '../src'

const FAKE_UUID = '6a15e73d-5edc-4b90-9d2b-bf8fd0a133c1'

describe('Http Client', () => {
const state: {
client?: MessagingClient
clientId?: uuid
clientToken?: string
user?: User
conversation?: Conversation
message?: Message
} = {}

test('Create client', async () => {
const client = new MessagingClient({
url: 'http://localhost:3100'
})

state.client = client
})

test('Sync', async () => {
const res = await state.client?.syncs.sync({})
expect(res!.id).toBeDefined()
expect(res!.token).toBeDefined()
expect(res!.webhooks).toEqual([])

state.clientId = res!.id
state.clientToken = res!.token

state.client!.authenticate(res!.id, res!.token)
})

test('Create user', async () => {
const user = await state.client!.users.create()
expect(user.clientId).toBe(state.clientId)
expect(user.id).toBeDefined()

state.user = user
})

test('Get user', async () => {
const user = await state.client!.users.get(state.user!.id)
expect(user).toEqual(state.user)
})

test('Get user that does not exist', async () => {
const user = await state.client!.users.get(FAKE_UUID)
expect(user).toBeUndefined()
})

test('Create conversation', async () => {
const conversation = await state.client!.conversations.create(state.user!.id)
expect(conversation.clientId).toBe(state.clientId)
expect(conversation.userId).toBe(state.user!.id)
expect(conversation.id).toBeDefined()
expect(conversation.createdOn).toBeDefined()

state.conversation = conversation
})

test('Get conversation', async () => {
const conversation = await state.client!.conversations.get(state.conversation!.id)
expect(conversation).toEqual(state.conversation)
})

test('Get conversation that does not exist', async () => {
const conversation = await state.client!.conversations.get(FAKE_UUID)
expect(conversation).toBeUndefined()
})

test('Create message', async () => {
const payload = {
type: 'text',
text: 'yoyo'
}

const message = await state.client!.messages.create(state.conversation!.id, state.user!.id, payload)
expect(message.conversationId).toBe(state.conversation!.id)
expect(message.authorId).toBe(state.user!.id)
expect(message.id).toBeDefined()
expect(message.sentOn).toBeDefined()
expect(message.payload).toEqual(payload)

state.message = message
})

test('Get message', async () => {
const message = await state.client!.messages.get(state.message!.id)
expect(message).toEqual(state.message)
})

test('Get message that does not exist', async () => {
const message = await state.client!.messages.get(FAKE_UUID)
expect(message).toBeUndefined()
})

test('Delete message', async () => {
const deleted = await state.client!.messages.delete(state.message!.id)
expect(deleted).toEqual(true)
})

test('Delete deleted message that does not exist', async () => {
const deleted = await state.client!.messages.delete(state.message!.id)
expect(deleted).toEqual(false)
})
})
7 changes: 7 additions & 0 deletions packages/client/test/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../../tsconfig.packages.json",
"compilerOptions": {
"rootDir": ".."
},
"include": ["../test/**/*", "../src/**/*"]
}
1 change: 1 addition & 0 deletions packages/client/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
"declaration": true,
"sourceMap": false
},
"include": ["src"],
"exclude": ["dist", "node_modules"]
}
Loading

0 comments on commit c8aa881

Please sign in to comment.