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

Changing how we deal with resources #118

Merged
merged 31 commits into from
Feb 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8101235
Fixing proxy path for graphql
einari Feb 19, 2021
666c29f
Fixing ports
einari Feb 19, 2021
1f7ba31
Merge branch 'main' of github.com:dolittle-entropy/applications-node …
einari Feb 19, 2021
83dce9e
Started setting up the basics of the resource configuration system
einari Feb 19, 2021
ff38bbc
Resource system ready for use
einari Feb 20, 2021
c2f08a2
Introducing support for custom types for mongodb driver
einari Feb 20, 2021
92affc7
Started transitioning away from typegoose/mongoose
einari Feb 20, 2021
eca0dfa
Up and running with multi tenanted MongoClient + MongoDb
einari Feb 20, 2021
e65709a
Adding extensions the make it unobtrusive to use MongoDB and automati…
einari Feb 21, 2021
1a8cb6e
Adding JSDocs
einari Feb 21, 2021
7456c7e
Making it possible to take a dependency to configuration directly
einari Feb 21, 2021
0761d08
Updating env variables documentation
einari Feb 21, 2021
5c164d2
Adding default resources.json file
einari Feb 21, 2021
f3f5a43
Adding some basics for documentation
einari Feb 21, 2021
3aa7264
Updating anatomy docs
einari Feb 21, 2021
3812bb3
Fixing anatomy docs
einari Feb 21, 2021
1cf8378
Adding details on context
einari Feb 21, 2021
a4bfd46
Setting up projections using the new provider system for configuration
einari Feb 21, 2021
c81550e
Moving Dev Dependencies to dependencies
einari Feb 21, 2021
483bc5b
Putting in docs on middlewares
einari Feb 21, 2021
ade1bec
Removing whitespace
einari Feb 21, 2021
f30cd7f
Changing to use the EventStoreConfiguration for the intermediates
einari Feb 21, 2021
9989173
Lint fixes
einari Feb 21, 2021
750227f
Disabling ESLint rules that doesn't make sense in the context
einari Feb 21, 2021
280532c
Fixing casing on methods
einari Feb 26, 2021
16cc1db
Adding an improved description around custom types as to why
einari Feb 26, 2021
fadfd48
Adding more details on resources and thinking behind it
einari Feb 26, 2021
76daabf
Fixing Vanir.json files to not have DB/EventStore configs
einari Feb 26, 2021
af78b04
Moving EventStoreConfiguration into Dolittle folder
einari Feb 26, 2021
f275819
Add information about Cursors and find methods
einari Feb 26, 2021
f9787e6
Fixing reference to event store configuration
einari Feb 26, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
"version": "0.2.0",
"configurations": [
{
"name": "Attach by Process ID",
"processId": "${command:PickProcess}",
"request": "attach",
"name": "Launch Basic Sample",
"type": "node",
"request": "launch",
"runtimeExecutable": "node",
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"],
"args": ["${workspaceFolder}/Samples/Source/Typescript/Backend/index.ts"],
"cwd": "${workspaceFolder}/Samples/Source/Typescript/Backend",
"preLaunchTask": "tsc: build - Typescript Sample",
"skipFiles": [
"<node_internals>/**"
],
"type": "pwa-node"
"<node_internals>/**",
"node_modules/**"
]
}
]
}
}
1 change: 1 addition & 0 deletions Documentation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ for everyone participating in this project to see what is expected.
| [Microservice Instance](./microservice.md) | How a Vanir based Dolittle microservice is packaged and run |
| [Frontend](./frontend/index.md) | Details about the frontend support |
| [Getting started](./getting-started.md) | A quick guide on getting started |
| [TypeScript Backend](./backend/typescript/index.md) | Topics specific for TypeScript based backends |
Original file line number Diff line number Diff line change
Expand Up @@ -71,84 +71,23 @@ In the backend you would then have a starting point for the microservice; `index
Leveraging the shared backend setup.

```javascript
import path from 'path';
import { startBackend } from '@shared/backend';

import { getSchema } from './schema';
import { ProductAdded, ProductHandler } from './configuration';
import 'reflect-metadata';
import { Host } from '@dolittle/vanir-backend';

(async () => {
const schema = await getSchema(); <-- This is the exposed GraphQL schema exposed

await startBackend({
microserviceId: '08fe9d6d-874e-45d5-b4f6-b31a099645a3', <-- Unique identifier that will be used for the microservice configuration in general
prefix: '/_/<microservice>', <-- URL prefix for frontend, APIs and GraphQL endpoints - each microservice has their own unique
publicPath: './public', <-- The path to where the static web pages are served from (if any)
port: 3003, <-- Development port the backend will be served from - must be unique per Microservice
dolittleRuntimePort: 50057, <-- The Dolittle runtime port to connect to in the local development environment
graphQLSchema: schema, <-- Pass in the GraphQL schema generated
defaultDatabaseName: '<microservice>', <-- Default name for database - unique per microservice
defaultEventStoreDatabaseName: <microservice-event-store>, <-- The default name for the event store database - same as in the resources.json for the microservice in environments.
expressCallback: _ => {
/* _ is the Express app instance */
await Host.start({
graphQLResolvers: [] // Array of graphql resolvers
expressCallback: (app) => {
},
dolittleCallback: _ => _
/*
_ is the Dolittle client builder instance

this is where you'd start registering things like
events, projections and more.
*/
});
dolittleCallback: (dolittle) => {
}
});
})();
```

For the GraphQL schema, add a file called `schema.ts`. The code above relies on this to be there.
A starting point would be to put it something that doesn't add any specific model or queries.

> The GraphQL system requires something, so one can't pass an empty schema.

Add the "empty" schema:

```javascript
import { buildSchema, Field, ObjectType, Query, Resolver, ResolverData } from 'type-graphql';
import { modelOptions, Severity } from '@typegoose/typegoose';
import { guid, GuidScalar } from '@shared/backend/data';
import { Guid } from '@dolittle/rudiments';
import { GraphQLSchema } from 'graphql';
import { container } from 'tsyringe';

@ObjectType()
@modelOptions({ options: { allowMixed: Severity.ALLOW } })
class Nothing {
@Field({ name: 'id' })
@guid()
_id?: Guid;
}

@Resolver(Nothing)
class NoQueries {
@Query(returns => [Nothing])
async noresults() {
return [];
}
}
Any GraphQL resolvers can then be added to the array of graphql resolvers, be it queries or mutations.

export async function getSchema(): Promise<GraphQLSchema> {
const schema = await buildSchema({
resolvers: [NoQueries],
container: {
get(someClass: any, resolverData: ResolverData<any>): any | Promise<any> {
return container.resolve(someClass);
}
},
scalarsMap: [
{ type: Guid, scalar: GuidScalar }
]
});
return schema;
}
```
> Apollo crashes if you add mutations here and no query - if all you have are mutations, you should add a query that doesn't do anything.

## APIs

Expand Down Expand Up @@ -194,47 +133,25 @@ import { RegisterRoutes } from './routes';
import * as swaggerDoc from './swagger.json';
```

Within the `startBackend()` call block, you can now add the swagger doc into it:
Within the `Host.start()` call block, you can now add the swagger doc into it:

```javascript
import path from 'path';
import { startBackend } from '@shared/backend';

import { getSchema } from './schema';
import { ProductAdded, ProductHandler } from './configuration';

import 'reflect-metadata';
import { Host } from '@dolittle/vanir-backend';
import { RegisterRoutes } from './routes';
const swaggerDoc = require('./swagger.json');
import * as swaggerDoc from './swagger.json';

(async () => {
const schema = await getSchema();

await startBackend({
microserviceId: '08fe9d6d-874e-45d5-b4f6-b31a099645a3',
prefix: '/_/<microservice>',
publicPath: './public',
port: 3003,
dolittleRuntimePort: 50057,
graphQLSchema: schema,
defaultDatabaseName: '<microservice>',
defaultEventStoreDatabaseName: <microservice-event-store>,
swaggerDoc, // This is the swagger doc.
expressCallback: _ => {
/* _ is the Express app instance */
},
dolittleCallback: _ => _
/*
_ is the Dolittle client builder instance

this is where you'd start registering things like
events, projections and more.
*/
});
await Host.start({
swaggerDoc, // This is the swagger doc.
expressCallback: (app) => {
RegisterRoutes(app); // Register the routes
}
});
})();
```

With this, you'll now have a new swagger endpoint and all your APIs accessible, prefixed with what you have set as prefix.
You should therefor be able to navigate to the URL e.g. http://localhost:3003/_/mymicroservice/api/swagger.

Read more about TSOA and concrete samples [here](https://tsoa-community.github.io/docs/examples.html).

36 changes: 36 additions & 0 deletions Documentation/backend/typescript/context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Context

As part of every web request coming into the system, there is an object that is set up that
can be retrieved anywhere as part of the request. This holds the following:

```typescript
{
userId: string;
tenantId: TenantId;
cookies: string;
}
```

To access it, all you need to do is use the `getCurrentContext()` function from the context.

```typescript
import { getCurrentContext } from '@dolittle/vanir-backend/dist/web';


const context = getCurrentContext();
```

## Express Middleware

The setting of this context is done through an express middleware.
It looks at the HTTP header and sets up the context for the current request coming in.
The default setup gets set up with this, but if you have your own setup and want to leverage
this functionality - you can do so through the following:

```typescript
import express from 'express';
import { ContextMiddleware } from '@dolittle/vanir-backend/dist/web';

const app = express();
app.use(ContextMiddleware);
```
16 changes: 16 additions & 0 deletions Documentation/backend/typescript/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# TypeScript Backend

## Table of contents

| Title | Description |
| ----- | ----------- |
| [Anatomy](./anatomy-of-a-backend.md) | The anatomy of a TypeScript based backend |
| [IoC](./ioc.md) | How to leverage the configured IoC container |
| [Resources](./resources.md) | How to use the resource system in your backend |
| [MongoDB](./mongodb.md) | How to use MongoDB in your backend |
| [GraphQL](./graphql.md) | How to use GraphQL in your backend |
| [Context](./context.md) | The context that is for the current web request |
| [Logging](./logging.md) | How to use structured logging in your backend |
| [Debugging](./debugging.md) | How to use debug your solution |
| [Shared Projects](./shared-projects.md) | What are the shared projects from the template? |
| [WebPack](./webpack.md) | How webpack works for your backend |
Loading