HATEOAS-first backend framework.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
3.8 KiB

  1. import {describe, it, expect, beforeAll, afterAll} from 'vitest';
  2. import {
  3. App,
  4. app,
  5. AppOperations,
  6. DataSource,
  7. Endpoint,
  8. endpoint, EndpointOperations,
  9. Operation,
  10. operation,
  11. validation as v,
  12. } from '../src/common';
  13. import {Backend, backend, Server} from '../src/backend';
  14. import {Client} from '../src/client';
  15. import {server} from '../src/extenders/http/backend/core';
  16. import {client} from '../src/extenders/http/client';
  17. const op = operation({
  18. name: 'create' as const,
  19. method: 'POST' as const,
  20. });
  21. const e = endpoint({
  22. name: 'e' as const,
  23. schema: v.object({}),
  24. })
  25. .can('create');
  26. const a = app({
  27. name: 'foo' as const,
  28. })
  29. .operation(op)
  30. .endpoint(e);
  31. describe('app', () => {
  32. let theApp: App;
  33. let theBackend: Backend;
  34. let theClient: Client;
  35. let theDataSource: DataSource;
  36. let theEndpoint: Endpoint;
  37. let theServer: Server;
  38. let theOperation: Operation;
  39. beforeAll(async () => {
  40. theOperation = operation({
  41. name: 'fetch' as const,
  42. });
  43. theEndpoint = endpoint({
  44. name: 'users' as const,
  45. schema: v.object({
  46. username: v.string()
  47. }),
  48. })
  49. .param('resourceId')
  50. .can('fetch');
  51. theApp = app({
  52. name: 'foo' as const
  53. })
  54. .operation(theOperation)
  55. .endpoint(theEndpoint);
  56. theBackend = backend({
  57. app: theApp
  58. });
  59. // add recipes function that will wrap app and backend to add operations and implement them, and will return a set
  60. // of operations.
  61. //
  62. // recipes should have a backend and client counterpart.
  63. theBackend.implementOperation('fetch', async (ctx) => {
  64. // noop
  65. });
  66. theServer = server({
  67. backend: theBackend
  68. });
  69. const connectionParams = {
  70. port: 3000,
  71. };
  72. await theServer.serve(connectionParams);
  73. theClient = client({
  74. app: theApp
  75. });
  76. await theClient.connect(connectionParams);
  77. });
  78. afterAll(async () => {
  79. await theClient.disconnect();
  80. await theServer.close();
  81. });
  82. it('works', async () => {
  83. const response = await theClient
  84. .at(theEndpoint, { resourceId: 3 })
  85. .makeRequest(theOperation);
  86. expect(response).toHaveProperty('status', 422);
  87. });
  88. });
  89. // const theEndpoint = endpoint({
  90. // schema: v.object({
  91. // username: v.string(),
  92. // }),
  93. // })
  94. // .can('patch')
  95. // .can('query');
  96. //
  97. // const canPatch = operation({
  98. // name: 'patch' as const,
  99. // args: [
  100. // 'merge',
  101. // 'delta',
  102. // ] as const,
  103. // // TODO define resource-specific stuff, like defining URL params, etc.
  104. // });
  105. //
  106. // const canFetch = operation({
  107. // name: 'fetch' as const,
  108. // args: [
  109. // 'item',
  110. // 'default',
  111. // ] as const,
  112. // });
  113. //
  114. // const canQuery = operation({
  115. // name: 'query' as const,
  116. // });
  117. //
  118. // const canCreate = operation({
  119. // name: 'create' as const,
  120. // });
  121. //
  122. // const canEmplace = operation({
  123. // name: 'emplace' as const,
  124. // });
  125. //
  126. // const canDelete = operation({
  127. // name: 'delete' as const,
  128. // });
  129. //
  130. // export const theApp = app({
  131. // name: 'foo' as const,
  132. // })
  133. // .operation(canQuery)
  134. // .operation(canPatch)
  135. // .operation(canFetch)
  136. // .operation(canCreate)
  137. // .operation(canEmplace)
  138. // .operation(canDelete)
  139. // .endpoint(theEndpoint);
  140. // //
  141. // // const bootstrap = async (theApp: App) => {
  142. // // if (typeof window === 'undefined') {
  143. // // const { backend } = await import('./backend');
  144. // // const theBackend = backend({
  145. // // app: theApp
  146. // // });
  147. // // }
  148. // // };
  149. //
  150. // const b = backend({
  151. // app: theApp,
  152. // })
  153. // .implementOperation({
  154. // operation: 'fetch' as const,
  155. // implementation: ({
  156. // endpoint,
  157. // arg
  158. // }) => {
  159. // switch (arg) {
  160. // case 'default': {
  161. //
  162. // }
  163. // }
  164. // },
  165. // });
  166. //
  167. // const s = server({
  168. // backend: b,
  169. // })
  170. // .serve({
  171. // host: '0.0.0.0',
  172. // port: 3000,
  173. // basePath: '/api'
  174. // });