Skip to content

Commit 492785f

Browse files
authored
Merge pull request #295 from hypercerts-org/develop
Deploy api V2 to prod
2 parents 3afddb0 + ff9aa3e commit 492785f

File tree

256 files changed

+22123
-7161
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

256 files changed

+22123
-7161
lines changed

.env.template

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,5 @@ SENTRY_AUTH_TOKEN="" #disabled for local
3030
# https://www.alchemy.com/
3131
ALCHEMY_API_KEY=""
3232

33-
# https://www.infura.io/
34-
INFURA_API_KEY=""
35-
3633
# https://drpc.org/
3734
DRPC_API_KEY=""

.github/workflows/ci-test-unit.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ jobs:
1818

1919
ALCHEMY_API_KEY: ${{ secrets.ALCHEMY_API_KEY }}
2020
DRPC_API_KEY: "test"
21-
INFURA_API_KEY: "test"
2221
FILECOIN_API_KEY: "test"
2322

2423
INDEXER_ENVIRONMENT: "test"

.gitignore

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ yarn-error.log*
3636
*.tsbuildinfo
3737
next-env.d.ts
3838

39-
# generated graphql files
40-
src/generated/
41-
4239
dist
4340
.rollup.cache
4441
.idea
42+
43+
# generated swagger files
44+
src/__generated__/

README.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ The API implements a fallback to the first available RPC. You can set the RPCs i
2828

2929
### Supabase
3030

31-
* Install Docker
32-
* `git submodule init`
33-
* `git submodule update --remote`
34-
* `pnpm supabase:start:all`
31+
- Install Docker
32+
- `git submodule init`
33+
- `git submodule update --remote`
34+
- `pnpm supabase:start:all`
3535

3636
This will spin up 2 Supabase instances in Docker, one for the indexer service (caching) and one for the data service (static data) which are both exposed by the API.
3737

@@ -43,21 +43,21 @@ From both instances, you can get their respective keys and add them to the env v
4343

4444
This will run a live production instance by running `swc` to compile the code and `nodemon` to restart the server on changes.
4545

46-
You can then find the API at `localhost:4000/spec` (Swagger instance) and the GraphQL at `localhost:4000/v1/graphql`
46+
You can then find the API at `localhost:4000/spec` (Swagger instance) and the GraphQL at `localhost:4000/v2/graphql`
4747

4848
## Deployments
4949

5050
Production: `https://api.hypercerts.org/`
5151
Staging: `https://staging-api.hypercerts.org`
5252

5353
`/spec` - Swagger instance documenting the API and exposing a playground to experiment with the endpoints
54-
`/v1/graphql` - GraphQL API to access hypercerts data like claims, fractions, attestations, allow lists
54+
`/v2/graphql` - GraphQL API to access hypercerts data like claims, fractions, attestations, allow lists
5555

5656
## Scripts
5757

5858
- `dev`: Starts the development server using `nodemon`, which will automatically restart the server whenever you save a file that the server uses.
5959
- `build`: Denerates the OpenAPI specification and routes using `tsoa`, and then compiles the TypeScript code into JavaScript using `swc`. The compiled code is output to the `dist` directory.
60-
- `start`: Starts the application in production mode.
60+
- `start`: Starts the application in production mode.
6161
- `lint`: Runs `eslint` on the codebase to check for linting errors.
6262
- `test`: Runs tests using `vitest`
6363

@@ -86,38 +86,38 @@ The API also provides an upload and validation endpoint for hypercert and allow
8686
graph TB
8787
Client[Client Applications]
8888
API[Hypercerts API :4000]
89-
89+
9090
subgraph "API Endpoints"
9191
Swagger["/spec\nSwagger Documentation"]
92-
GraphQL["/v1/graphql\nGraphQL Endpoint"]
92+
GraphQL["/v2/graphql\nGraphQL Endpoint"]
9393
Upload["Upload & Validation\nEndpoints"]
9494
end
95-
95+
9696
subgraph "Data Services"
9797
Static[("Static Data Service\n(Supabase DB)\n- User Data\n- Collections\n- Signed Orders")]
9898
Indexer[("Indexer Service\n(Supabase DB)\n- On-chain Data\n- IPFS Data")]
9999
end
100-
100+
101101
subgraph "External Services"
102102
IPFS[(IPFS\nMetadata Storage)]
103103
Blockchain[(Blockchain\nSupported Chains)]
104104
EAS[(EAS\nAttestations)]
105105
end
106-
106+
107107
Client --> API
108108
API --> Swagger
109109
API --> GraphQL
110110
API --> Upload
111-
111+
112112
GraphQL --> Static
113113
GraphQL --> Indexer
114114
Upload --> IPFS
115-
115+
116116
Indexer --> Blockchain
117117
Indexer --> IPFS
118118
Indexer --> EAS
119-
119+
120120
class Swagger,GraphQL,Upload apiEndpoint;
121121
class Static,Indexer database;
122122
class IPFS,Blockchain,EAS external;
123-
```
123+
```

docs/DEVELOPMENT.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Development Guide: Implementing a New Entity
2+
3+
This guide explains how to implement a new entity in the Hypercerts API, from type definition to resolver implementation.
4+
5+
## Overview
6+
7+
The Hypercerts API uses a modular architecture where each entity follows a consistent pattern:
8+
9+
1. Type Definition
10+
2. Query Arguments
11+
3. Entity Service
12+
4. Resolver
13+
14+
## Step-by-Step Implementation
15+
16+
### 1. Define Entity Types
17+
18+
Create a new file in `src/graphql/schemas/typeDefs/` for your entity types:
19+
20+
```typescript
21+
// src/graphql/schemas/typeDefs/yourEntityTypeDefs.ts
22+
import { Field, ObjectType } from "type-graphql";
23+
import { BaseEntity } from "./baseTypes.js";
24+
25+
@ObjectType()
26+
export class YourEntity extends BaseEntity {
27+
@Field(() => String)
28+
name: string;
29+
30+
@Field(() => String, { nullable: true })
31+
description?: string;
32+
33+
// Add other fields as needed
34+
}
35+
36+
@ObjectType()
37+
export class GetYourEntitiesResponse {
38+
@Field(() => [YourEntity])
39+
data: YourEntity[];
40+
41+
@Field(() => Int)
42+
count: number;
43+
}
44+
```
45+
46+
### 2. Define Query Arguments
47+
48+
Create a new file in `src/graphql/schemas/args/` for your query arguments:
49+
50+
```typescript
51+
// src/graphql/schemas/args/yourEntityArgs.ts
52+
import { ArgsType } from "type-graphql";
53+
import { createEntityArgs } from "../../../lib/graphql/createEntityArgs.js";
54+
import { EntityTypeDefs } from "../typeDefs/typeDefs.js";
55+
56+
// Define your entity fields
57+
const fields = {
58+
name: "string",
59+
description: "string",
60+
// Add other fields as needed
61+
} as const;
62+
63+
// Create query arguments
64+
export const { WhereInput, SortOptions } = createEntityArgs(
65+
"YourEntity" as EntityTypeDefs,
66+
fields,
67+
);
68+
69+
@ArgsType()
70+
export class GetYourEntitiesArgs {
71+
first?: number;
72+
offset?: number;
73+
where?: typeof WhereInput;
74+
sortBy?: typeof SortOptions;
75+
}
76+
```
77+
78+
### 3. Create Entity Service
79+
80+
Create a new file in `src/services/database/entities/` for your entity service:
81+
82+
```typescript
83+
// src/services/database/entities/YourEntityService.ts
84+
import { injectable } from "tsyringe";
85+
import { createEntityService } from "./EntityServiceFactory.js";
86+
import { GetYourEntitiesArgs } from "../../../graphql/schemas/args/yourEntityArgs.js";
87+
import { YourEntity } from "../../../graphql/schemas/typeDefs/yourEntityTypeDefs.js";
88+
89+
@injectable()
90+
export class YourEntityService {
91+
private service = createEntityService<YourEntity, GetYourEntitiesArgs>(
92+
"your_entity_table",
93+
{
94+
// Add any custom query modifiers if needed
95+
},
96+
);
97+
98+
async getYourEntities(args: GetYourEntitiesArgs) {
99+
return this.service.getMany(args);
100+
}
101+
102+
async getYourEntity(args: GetYourEntitiesArgs) {
103+
return this.service.getSingle(args);
104+
}
105+
}
106+
```
107+
108+
### 4. Implement Resolver
109+
110+
Create a new file in `src/graphql/schemas/resolvers/` for your resolver:
111+
112+
```typescript
113+
// src/graphql/schemas/resolvers/yourEntityResolver.ts
114+
import { inject, injectable } from "tsyringe";
115+
import { Args, Query, Resolver } from "type-graphql";
116+
import { YourEntityService } from "../../../services/database/entities/YourEntityService.js";
117+
import { GetYourEntitiesArgs } from "../args/yourEntityArgs.js";
118+
import {
119+
GetYourEntitiesResponse,
120+
YourEntity,
121+
} from "../typeDefs/yourEntityTypeDefs.js";
122+
123+
@injectable()
124+
@Resolver(() => YourEntity)
125+
class YourEntityResolver {
126+
constructor(
127+
@inject(YourEntityService)
128+
private yourEntityService: YourEntityService,
129+
) {}
130+
131+
@Query(() => GetYourEntitiesResponse)
132+
async yourEntities(@Args() args: GetYourEntitiesArgs) {
133+
return this.yourEntityService.getYourEntities(args);
134+
}
135+
}
136+
```
137+
138+
### 5. Register the Resolver
139+
140+
Add your resolver to the list of resolvers in `src/graphql/schemas/resolvers/index.ts`:
141+
142+
```typescript
143+
export * from "./yourEntityResolver.js";
144+
```
145+
146+
## Best Practices
147+
148+
1. **Type Safety**: Always use TypeScript's type system to ensure type safety across your implementation.
149+
2. **Consistent Naming**: Follow the existing naming conventions in the codebase.
150+
3. **Error Handling**: Implement proper error handling in your service and resolver methods.
151+
4. **Testing**: Write unit tests for your new entity implementation.
152+
5. **Documentation**: Add JSDoc comments to document your types, methods, and classes.
153+
154+
## Example Implementation
155+
156+
For a complete example, you can look at the implementation of existing entities like `Contract`, `Metadata`, or `AttestationSchema` in the codebase.
157+
158+
## Common Pitfalls
159+
160+
1. **Type Registration**: Ensure all your types are properly registered in the GraphQL schema.
161+
2. **Dependency Injection**: Use the `@injectable()` and `@inject()` decorators correctly.
162+
3. **Query Arguments**: Make sure your query arguments match the expected structure.
163+
4. **Database Schema**: Ensure your database table matches the entity structure.
164+
165+
## Testing Your Implementation
166+
167+
1. Start the development server: `pnpm dev`
168+
2. Access the GraphQL playground at `http://localhost:4000/v2/graphql`
169+
3. Test your queries and mutations
170+
4. Run the test suite: `pnpm test`
171+
172+
## Additional Resources
173+
174+
- [TypeGraphQL Documentation](https://typegraphql.com/)
175+
- [Kysely Documentation](https://kysely.dev/docs/intro)
176+
- [Supabase Documentation](https://supabase.com/docs)

eslint.config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,14 @@ export default tseslint.config(
99
"@typescript-eslint/no-extraneous-class": "off",
1010
},
1111
},
12+
{
13+
files: ["**/*.test.ts"],
14+
rules: {
15+
"@typescript-eslint/no-explicit-any": "off",
16+
"@typescript-eslint/no-unused-vars": [
17+
"error",
18+
{ argsIgnorePattern: "^_" },
19+
],
20+
},
21+
},
1222
);

lib/hypercerts-indexer

Submodule hypercerts-indexer updated 56 files

0 commit comments

Comments
 (0)