openskill-ai 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +230 -0
- package/dist/chunk-63EFN7CX.js +450 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +286 -0
- package/dist/index.d.ts +158 -0
- package/dist/index.js +391 -0
- package/package.json +70 -0
- package/skills/backend-best-practices/SKILL.md +116 -0
- package/skills/backend-best-practices/rules/api-consistent-responses.md +127 -0
- package/skills/backend-best-practices/rules/api-pagination.md +83 -0
- package/skills/backend-best-practices/rules/api-rate-limiting.md +94 -0
- package/skills/backend-best-practices/rules/api-restful-conventions.md +67 -0
- package/skills/backend-best-practices/rules/api-versioning.md +69 -0
- package/skills/backend-best-practices/rules/arch-dependency-injection.md +55 -0
- package/skills/backend-best-practices/rules/arch-dto-pattern.md +64 -0
- package/skills/backend-best-practices/rules/arch-repository-pattern.md +74 -0
- package/skills/backend-best-practices/rules/arch-separation-concerns.md +80 -0
- package/skills/backend-best-practices/rules/arch-service-layer.md +48 -0
- package/skills/backend-best-practices/rules/code-documentation.md +77 -0
- package/skills/backend-best-practices/rules/code-dry-principle.md +49 -0
- package/skills/backend-best-practices/rules/code-naming-conventions.md +47 -0
- package/skills/backend-best-practices/rules/code-single-responsibility.md +78 -0
- package/skills/backend-best-practices/rules/code-type-safety.md +64 -0
- package/skills/backend-best-practices/rules/db-connection-pooling.md +136 -0
- package/skills/backend-best-practices/rules/db-indexing.md +88 -0
- package/skills/backend-best-practices/rules/db-migrations.md +189 -0
- package/skills/backend-best-practices/rules/db-n-plus-one.md +118 -0
- package/skills/backend-best-practices/rules/db-transactions.md +178 -0
- package/skills/backend-best-practices/rules/deploy-environment-variables.md +63 -0
- package/skills/backend-best-practices/rules/deploy-graceful-shutdown.md +77 -0
- package/skills/backend-best-practices/rules/deploy-health-checks.md +70 -0
- package/skills/backend-best-practices/rules/deploy-monitoring.md +87 -0
- package/skills/backend-best-practices/rules/deploy-zero-downtime.md +85 -0
- package/skills/backend-best-practices/rules/error-global-handler.md +94 -0
- package/skills/backend-best-practices/rules/error-graceful-degradation.md +70 -0
- package/skills/backend-best-practices/rules/error-http-status-codes.md +77 -0
- package/skills/backend-best-practices/rules/error-logging.md +71 -0
- package/skills/backend-best-practices/rules/error-meaningful-messages.md +61 -0
- package/skills/backend-best-practices/rules/perf-async-operations.md +55 -0
- package/skills/backend-best-practices/rules/perf-caching.md +81 -0
- package/skills/backend-best-practices/rules/perf-compression.md +33 -0
- package/skills/backend-best-practices/rules/perf-database-queries.md +54 -0
- package/skills/backend-best-practices/rules/perf-lazy-loading.md +47 -0
- package/skills/backend-best-practices/rules/security-https-only.md +116 -0
- package/skills/backend-best-practices/rules/security-input-validation.md +96 -0
- package/skills/backend-best-practices/rules/security-jwt-best-practices.md +140 -0
- package/skills/backend-best-practices/rules/security-sql-injection.md +77 -0
- package/skills/clean-code-skills/references/solid.md +304 -0
- package/skills/clean-code-skills/skills.md +263 -0
- package/skills/flutter-skills/AGENTS.md +1265 -0
- package/skills/flutter-skills/SKILL.md +116 -0
- package/skills/flutter-skills/rules/advanced-custom-painter.md +117 -0
- package/skills/flutter-skills/rules/advanced-layer-link.md +103 -0
- package/skills/flutter-skills/rules/advanced-render-object.md +105 -0
- package/skills/flutter-skills/rules/advanced-sliver-persistent.md +111 -0
- package/skills/flutter-skills/rules/animation-animated-builder.md +118 -0
- package/skills/flutter-skills/rules/animation-cached-images.md +112 -0
- package/skills/flutter-skills/rules/animation-physics.md +105 -0
- package/skills/flutter-skills/rules/animation-reduce-overdraw.md +111 -0
- package/skills/flutter-skills/rules/animation-tween-sequence.md +112 -0
- package/skills/flutter-skills/rules/async-cancel-subscriptions.md +112 -0
- package/skills/flutter-skills/rules/async-compute.md +78 -0
- package/skills/flutter-skills/rules/async-debounce-throttle.md +104 -0
- package/skills/flutter-skills/rules/async-future-builder.md +106 -0
- package/skills/flutter-skills/rules/async-parallel.md +75 -0
- package/skills/flutter-skills/rules/build-avoid-rebuild.md +80 -0
- package/skills/flutter-skills/rules/build-const-constructors.md +56 -0
- package/skills/flutter-skills/rules/build-itemextent.md +73 -0
- package/skills/flutter-skills/rules/build-keys.md +74 -0
- package/skills/flutter-skills/rules/build-split-widgets.md +99 -0
- package/skills/flutter-skills/rules/dart-avoid-dynamic.md +86 -0
- package/skills/flutter-skills/rules/dart-cascade-notation.md +89 -0
- package/skills/flutter-skills/rules/dart-collection-if.md +92 -0
- package/skills/flutter-skills/rules/dart-final-const.md +70 -0
- package/skills/flutter-skills/rules/dart-spread-operator.md +90 -0
- package/skills/flutter-skills/rules/dart-string-buffer.md +77 -0
- package/skills/flutter-skills/rules/layout-avoid-opacity.md +110 -0
- package/skills/flutter-skills/rules/layout-clip-behavior.md +94 -0
- package/skills/flutter-skills/rules/layout-intrinsic-dimensions.md +89 -0
- package/skills/flutter-skills/rules/layout-repaint-boundary.md +117 -0
- package/skills/flutter-skills/rules/layout-slivers.md +94 -0
- package/skills/flutter-skills/rules/memory-dispose.md +90 -0
- package/skills/flutter-skills/rules/memory-image-cache.md +86 -0
- package/skills/flutter-skills/rules/memory-isolate.md +91 -0
- package/skills/flutter-skills/rules/memory-precache.md +114 -0
- package/skills/flutter-skills/rules/memory-weak-references.md +79 -0
- package/skills/flutter-skills/rules/state-late-final.md +90 -0
- package/skills/flutter-skills/rules/state-lift-state-up.md +84 -0
- package/skills/flutter-skills/rules/state-minimize-rebuilds.md +95 -0
- package/skills/flutter-skills/rules/state-selector.md +87 -0
- package/skills/flutter-skills/rules/state-valuenotifier.md +85 -0
- package/skills/frontend-design/SKILL.md +42 -0
- package/skills/skill-writer-skills/AGENTS.md +637 -0
- package/skills/skill-writer-skills/README.md +49 -0
- package/skills/skill-writer-skills/SKILL.md +97 -0
- package/skills/skill-writer-skills/metadata.json +17 -0
- package/skills/skill-writer-skills/references/common-pitfalls.md +291 -0
- package/skills/skill-writer-skills/references/core-principles.md +147 -0
- package/skills/skill-writer-skills/references/creation-process.md +250 -0
- package/skills/skill-writer-skills/references/design-patterns.md +300 -0
- package/skills/skill-writer-skills/references/skill-anatomy.md +174 -0
- package/skills/skill-writer-skills/references/validation-checklist.md +194 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Set Up Monitoring and Alerts
|
|
3
|
+
impact: LOW-MEDIUM
|
|
4
|
+
impactDescription: Enables proactive issue detection and resolution
|
|
5
|
+
tags: deployment, monitoring, observability, alerts
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Set Up Monitoring and Alerts
|
|
9
|
+
|
|
10
|
+
Implement monitoring and alerting to detect issues before they impact users.
|
|
11
|
+
|
|
12
|
+
**Correct implementation:**
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
// Application Performance Monitoring (APM)
|
|
16
|
+
const newrelic = require('newrelic'); // or DataDog, AppDynamics, etc.
|
|
17
|
+
|
|
18
|
+
// Custom metrics
|
|
19
|
+
const promClient = require('prom-client');
|
|
20
|
+
|
|
21
|
+
// Create metrics
|
|
22
|
+
const httpRequestDuration = new promClient.Histogram({
|
|
23
|
+
name: 'http_request_duration_seconds',
|
|
24
|
+
help: 'Duration of HTTP requests in seconds',
|
|
25
|
+
labelNames: ['method', 'route', 'status_code']
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const activeConnections = new promClient.Gauge({
|
|
29
|
+
name: 'active_connections',
|
|
30
|
+
help: 'Number of active connections'
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Middleware to track metrics
|
|
34
|
+
app.use((req, res, next) => {
|
|
35
|
+
const start = Date.now();
|
|
36
|
+
|
|
37
|
+
res.on('finish', () => {
|
|
38
|
+
const duration = (Date.now() - start) / 1000;
|
|
39
|
+
httpRequestDuration
|
|
40
|
+
.labels(req.method, req.route?.path || req.path, res.statusCode)
|
|
41
|
+
.observe(duration);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
next();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Expose metrics endpoint
|
|
48
|
+
app.get('/metrics', async (req, res) => {
|
|
49
|
+
res.set('Content-Type', promClient.register.contentType);
|
|
50
|
+
res.end(await promClient.register.metrics());
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Error tracking
|
|
54
|
+
const Sentry = require('@sentry/node');
|
|
55
|
+
|
|
56
|
+
Sentry.init({
|
|
57
|
+
dsn: process.env.SENTRY_DSN,
|
|
58
|
+
environment: process.env.NODE_ENV,
|
|
59
|
+
tracesSampleRate: 0.1,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
app.use(Sentry.Handlers.requestHandler());
|
|
63
|
+
app.use(Sentry.Handlers.errorHandler());
|
|
64
|
+
|
|
65
|
+
// Custom alerts
|
|
66
|
+
const alertSlack = async (message) => {
|
|
67
|
+
if (process.env.NODE_ENV === 'production') {
|
|
68
|
+
await fetch(process.env.SLACK_WEBHOOK_URL, {
|
|
69
|
+
method: 'POST',
|
|
70
|
+
body: JSON.stringify({ text: message })
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Monitor critical operations
|
|
76
|
+
app.post('/api/payments', async (req, res) => {
|
|
77
|
+
try {
|
|
78
|
+
const payment = await processPayment(req.body);
|
|
79
|
+
res.json(payment);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
await alertSlack(`Payment failed: ${error.message}`);
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Reference: [Monitoring Best Practices](https://www.datadoghq.com/blog/monitoring-101-collecting-data/)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Implement Zero-Downtime Deployments
|
|
3
|
+
impact: LOW-MEDIUM
|
|
4
|
+
impactDescription: Eliminates service interruption during deployments
|
|
5
|
+
tags: deployment, zero-downtime, continuous-deployment
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Implement Zero-Downtime Deployments
|
|
9
|
+
|
|
10
|
+
Use rolling deployments and health checks to deploy without downtime.
|
|
11
|
+
|
|
12
|
+
**Deployment strategies:**
|
|
13
|
+
|
|
14
|
+
```yaml
|
|
15
|
+
# Docker Compose - Rolling Update
|
|
16
|
+
version: '3'
|
|
17
|
+
services:
|
|
18
|
+
api:
|
|
19
|
+
image: myapp:latest
|
|
20
|
+
deploy:
|
|
21
|
+
replicas: 3
|
|
22
|
+
update_config:
|
|
23
|
+
parallelism: 1
|
|
24
|
+
delay: 10s
|
|
25
|
+
order: start-first
|
|
26
|
+
rollback_config:
|
|
27
|
+
parallelism: 1
|
|
28
|
+
delay: 5s
|
|
29
|
+
healthcheck:
|
|
30
|
+
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
|
31
|
+
interval: 30s
|
|
32
|
+
timeout: 10s
|
|
33
|
+
retries: 3
|
|
34
|
+
start_period: 40s
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
# Kubernetes - Rolling Update
|
|
39
|
+
apiVersion: apps/v1
|
|
40
|
+
kind: Deployment
|
|
41
|
+
metadata:
|
|
42
|
+
name: api-deployment
|
|
43
|
+
spec:
|
|
44
|
+
replicas: 3
|
|
45
|
+
strategy:
|
|
46
|
+
type: RollingUpdate
|
|
47
|
+
rollingUpdate:
|
|
48
|
+
maxSurge: 1
|
|
49
|
+
maxUnavailable: 0
|
|
50
|
+
template:
|
|
51
|
+
spec:
|
|
52
|
+
containers:
|
|
53
|
+
- name: api
|
|
54
|
+
image: myapp:latest
|
|
55
|
+
readinessProbe:
|
|
56
|
+
httpGet:
|
|
57
|
+
path: /health
|
|
58
|
+
port: 3000
|
|
59
|
+
initialDelaySeconds: 5
|
|
60
|
+
periodSeconds: 10
|
|
61
|
+
livenessProbe:
|
|
62
|
+
httpGet:
|
|
63
|
+
path: /health
|
|
64
|
+
port: 3000
|
|
65
|
+
initialDelaySeconds: 15
|
|
66
|
+
periodSeconds: 20
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Blue-Green Deployment:**
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Deploy new version (green)
|
|
73
|
+
docker-compose -f docker-compose.green.yml up -d
|
|
74
|
+
|
|
75
|
+
# Wait for health checks
|
|
76
|
+
sleep 30
|
|
77
|
+
|
|
78
|
+
# Switch traffic to green
|
|
79
|
+
nginx -s reload
|
|
80
|
+
|
|
81
|
+
# Stop old version (blue)
|
|
82
|
+
docker-compose -f docker-compose.blue.yml down
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Reference: [Zero-Downtime Deployment](https://martinfowler.com/bliki/BlueGreenDeployment.html)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Implement Global Error Handling
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Consistent error handling and prevents crashes
|
|
5
|
+
tags: error-handling, middleware, express, robustness
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Implement Global Error Handling
|
|
9
|
+
|
|
10
|
+
Use centralized error handling to catch errors consistently and prevent server crashes.
|
|
11
|
+
|
|
12
|
+
**Incorrect (inconsistent error handling):**
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
app.get('/api/users/:id', async (req, res) => {
|
|
16
|
+
try {
|
|
17
|
+
const user = await User.findById(req.params.id);
|
|
18
|
+
res.json(user);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
res.status(500).json({ error: 'Something went wrong' });
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Another endpoint with different error format
|
|
25
|
+
app.get('/api/posts/:id', async (req, res) => {
|
|
26
|
+
const post = await Post.findById(req.params.id); // Unhandled error!
|
|
27
|
+
res.json(post);
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Correct (global error handler):**
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
// Custom error class
|
|
35
|
+
class AppError extends Error {
|
|
36
|
+
constructor(message, statusCode) {
|
|
37
|
+
super(message);
|
|
38
|
+
this.statusCode = statusCode;
|
|
39
|
+
this.isOperational = true;
|
|
40
|
+
Error.captureStackTrace(this, this.constructor);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Async wrapper to avoid try-catch in every route
|
|
45
|
+
const asyncHandler = (fn) => (req, res, next) => {
|
|
46
|
+
Promise.resolve(fn(req, res, next)).catch(next);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Routes
|
|
50
|
+
app.get('/api/users/:id', asyncHandler(async (req, res) => {
|
|
51
|
+
const user = await User.findById(req.params.id);
|
|
52
|
+
if (!user) {
|
|
53
|
+
throw new AppError('User not found', 404);
|
|
54
|
+
}
|
|
55
|
+
res.json(user);
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
// Global error handler (must be last)
|
|
59
|
+
app.use((err, req, res, next) => {
|
|
60
|
+
err.statusCode = err.statusCode || 500;
|
|
61
|
+
err.status = err.status || 'error';
|
|
62
|
+
|
|
63
|
+
if (process.env.NODE_ENV === 'development') {
|
|
64
|
+
res.status(err.statusCode).json({
|
|
65
|
+
status: err.status,
|
|
66
|
+
error: err,
|
|
67
|
+
message: err.message,
|
|
68
|
+
stack: err.stack
|
|
69
|
+
});
|
|
70
|
+
} else {
|
|
71
|
+
// Production - don't leak stack traces
|
|
72
|
+
if (err.isOperational) {
|
|
73
|
+
res.status(err.statusCode).json({
|
|
74
|
+
status: err.status,
|
|
75
|
+
message: err.message
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
console.error('ERROR:', err);
|
|
79
|
+
res.status(500).json({
|
|
80
|
+
status: 'error',
|
|
81
|
+
message: 'Something went wrong'
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Handle unhandled promise rejections
|
|
88
|
+
process.on('unhandledRejection', (err) => {
|
|
89
|
+
console.error('UNHANDLED REJECTION:', err);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Reference: [Error Handling Best Practices](https://expressjs.com/en/guide/error-handling.html)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Implement Graceful Degradation
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Maintains service availability during partial failures
|
|
5
|
+
tags: error-handling, resilience, fault-tolerance
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Implement Graceful Degradation
|
|
9
|
+
|
|
10
|
+
Design systems to degrade gracefully when dependencies fail, maintaining core functionality.
|
|
11
|
+
|
|
12
|
+
**Incorrect (complete failure):**
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
app.get('/api/dashboard', async (req, res) => {
|
|
16
|
+
// If recommendations fail, entire endpoint fails
|
|
17
|
+
const userData = await getUserData(req.user.id);
|
|
18
|
+
const recommendations = await getRecommendations(req.user.id);
|
|
19
|
+
const analytics = await getAnalytics(req.user.id);
|
|
20
|
+
|
|
21
|
+
res.json({ userData, recommendations, analytics });
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Correct (graceful degradation):**
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
app.get('/api/dashboard', async (req, res) => {
|
|
29
|
+
const results = await Promise.allSettled([
|
|
30
|
+
getUserData(req.user.id),
|
|
31
|
+
getRecommendations(req.user.id),
|
|
32
|
+
getAnalytics(req.user.id)
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
const [userData, recommendations, analytics] = results;
|
|
36
|
+
|
|
37
|
+
res.json({
|
|
38
|
+
userData: userData.status === 'fulfilled'
|
|
39
|
+
? userData.value
|
|
40
|
+
: null,
|
|
41
|
+
recommendations: recommendations.status === 'fulfilled'
|
|
42
|
+
? recommendations.value
|
|
43
|
+
: [], // Fallback to empty array
|
|
44
|
+
analytics: analytics.status === 'fulfilled'
|
|
45
|
+
? analytics.value
|
|
46
|
+
: { message: 'Analytics temporarily unavailable' },
|
|
47
|
+
warnings: results
|
|
48
|
+
.filter(r => r.status === 'rejected')
|
|
49
|
+
.map(r => r.reason.message)
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// With circuit breaker pattern
|
|
54
|
+
const CircuitBreaker = require('opossum');
|
|
55
|
+
|
|
56
|
+
const breaker = new CircuitBreaker(getRecommendations, {
|
|
57
|
+
timeout: 3000,
|
|
58
|
+
errorThresholdPercentage: 50,
|
|
59
|
+
resetTimeout: 30000
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
breaker.fallback(() => []);
|
|
63
|
+
|
|
64
|
+
app.get('/api/dashboard', async (req, res) => {
|
|
65
|
+
const recommendations = await breaker.fire(req.user.id);
|
|
66
|
+
// Returns fallback if service is down
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Reference: [Fault Tolerance Patterns](https://martinfowler.com/articles/patterns-of-distributed-systems/)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Appropriate HTTP Status Codes
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Better API clarity and client-side error handling
|
|
5
|
+
tags: error-handling, http, status-codes, api
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Appropriate HTTP Status Codes
|
|
9
|
+
|
|
10
|
+
Return correct HTTP status codes to communicate the result of API requests clearly.
|
|
11
|
+
|
|
12
|
+
**Incorrect (always returns 200):**
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
app.get('/api/users/:id', async (req, res) => {
|
|
16
|
+
const user = await User.findById(req.params.id);
|
|
17
|
+
if (!user) {
|
|
18
|
+
return res.json({ error: 'User not found' }); // Still 200!
|
|
19
|
+
}
|
|
20
|
+
res.json(user);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
app.post('/api/users', async (req, res) => {
|
|
24
|
+
const user = await User.create(req.body);
|
|
25
|
+
res.json(user); // Should be 201!
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Correct (proper status codes):**
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
app.get('/api/users/:id', async (req, res) => {
|
|
33
|
+
const user = await User.findById(req.params.id);
|
|
34
|
+
if (!user) {
|
|
35
|
+
return res.status(404).json({ error: 'User not found' });
|
|
36
|
+
}
|
|
37
|
+
res.status(200).json(user);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
app.post('/api/users', async (req, res) => {
|
|
41
|
+
const user = await User.create(req.body);
|
|
42
|
+
res.status(201).json(user); // Created
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
app.put('/api/users/:id', async (req, res) => {
|
|
46
|
+
const user = await User.findByIdAndUpdate(req.params.id, req.body);
|
|
47
|
+
res.status(200).json(user); // OK
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
app.delete('/api/users/:id', async (req, res) => {
|
|
51
|
+
await User.findByIdAndDelete(req.params.id);
|
|
52
|
+
res.status(204).send(); // No Content
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Common Status Codes:**
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
// Success
|
|
60
|
+
200 OK - Request succeeded
|
|
61
|
+
201 Created - Resource created
|
|
62
|
+
204 No Content - Success but no response body
|
|
63
|
+
|
|
64
|
+
// Client Errors
|
|
65
|
+
400 Bad Request - Invalid input
|
|
66
|
+
401 Unauthorized - Authentication required
|
|
67
|
+
403 Forbidden - Not authorized
|
|
68
|
+
404 Not Found - Resource doesn't exist
|
|
69
|
+
409 Conflict - Duplicate/conflict
|
|
70
|
+
422 Unprocessable Entity - Validation failed
|
|
71
|
+
|
|
72
|
+
// Server Errors
|
|
73
|
+
500 Internal Server Error - Unexpected error
|
|
74
|
+
503 Service Unavailable - Server overloaded
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Reference: [HTTP Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Log Errors with Context
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Enables effective debugging and monitoring
|
|
5
|
+
tags: error-handling, logging, debugging, monitoring
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Log Errors with Context
|
|
9
|
+
|
|
10
|
+
Log errors with sufficient context for debugging, including request details and stack traces.
|
|
11
|
+
|
|
12
|
+
**Incorrect (insufficient logging):**
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
try {
|
|
16
|
+
await processPayment(orderId);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.log('Error'); // No context!
|
|
19
|
+
res.status(500).json({ error: 'Failed' });
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Correct (contextual logging):**
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
const winston = require('winston');
|
|
27
|
+
|
|
28
|
+
const logger = winston.createLogger({
|
|
29
|
+
level: 'info',
|
|
30
|
+
format: winston.format.combine(
|
|
31
|
+
winston.format.timestamp(),
|
|
32
|
+
winston.format.json()
|
|
33
|
+
),
|
|
34
|
+
transports: [
|
|
35
|
+
new winston.transports.File({ filename: 'error.log', level: 'error' }),
|
|
36
|
+
new winston.transports.File({ filename: 'combined.log' })
|
|
37
|
+
]
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
app.post('/api/payments', async (req, res) => {
|
|
41
|
+
try {
|
|
42
|
+
await processPayment(req.body.orderId);
|
|
43
|
+
res.json({ success: true });
|
|
44
|
+
} catch (error) {
|
|
45
|
+
logger.error('Payment processing failed', {
|
|
46
|
+
error: error.message,
|
|
47
|
+
stack: error.stack,
|
|
48
|
+
orderId: req.body.orderId,
|
|
49
|
+
userId: req.user?.id,
|
|
50
|
+
endpoint: req.path,
|
|
51
|
+
method: req.method,
|
|
52
|
+
timestamp: new Date().toISOString()
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
res.status(500).json({ error: 'Payment failed' });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Request logging middleware
|
|
60
|
+
app.use((req, res, next) => {
|
|
61
|
+
logger.info('Request received', {
|
|
62
|
+
method: req.method,
|
|
63
|
+
path: req.path,
|
|
64
|
+
userId: req.user?.id,
|
|
65
|
+
ip: req.ip
|
|
66
|
+
});
|
|
67
|
+
next();
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Reference: [Logging Best Practices](https://www.datadoghq.com/blog/node-logging-best-practices/)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Provide Meaningful Error Messages
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Improves debugging and user experience
|
|
5
|
+
tags: error-handling, ux, debugging
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Provide Meaningful Error Messages
|
|
9
|
+
|
|
10
|
+
Return clear, actionable error messages to help clients understand and fix issues.
|
|
11
|
+
|
|
12
|
+
**Incorrect (vague errors):**
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
if (!user) {
|
|
16
|
+
return res.status(400).json({ error: 'Error' });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (age < 18) {
|
|
20
|
+
return res.status(400).json({ error: 'Invalid' });
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Correct (descriptive errors):**
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
if (!user) {
|
|
28
|
+
return res.status(404).json({
|
|
29
|
+
error: 'User not found',
|
|
30
|
+
code: 'USER_NOT_FOUND',
|
|
31
|
+
details: `No user exists with ID: ${userId}`
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (age < 18) {
|
|
36
|
+
return res.status(400).json({
|
|
37
|
+
error: 'Validation failed',
|
|
38
|
+
code: 'AGE_REQUIREMENT_NOT_MET',
|
|
39
|
+
details: 'User must be at least 18 years old',
|
|
40
|
+
field: 'age',
|
|
41
|
+
receivedValue: age,
|
|
42
|
+
expectedValue: '>=18'
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Validation errors
|
|
47
|
+
const errors = validationResult(req);
|
|
48
|
+
if (!errors.isEmpty()) {
|
|
49
|
+
return res.status(422).json({
|
|
50
|
+
error: 'Validation failed',
|
|
51
|
+
code: 'VALIDATION_ERROR',
|
|
52
|
+
details: errors.array().map(err => ({
|
|
53
|
+
field: err.param,
|
|
54
|
+
message: err.msg,
|
|
55
|
+
value: err.value
|
|
56
|
+
}))
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Reference: [API Error Handling](https://www.baeldung.com/rest-api-error-handling-best-practices)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Async/Await for I/O Operations
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Prevents blocking and improves concurrency
|
|
5
|
+
tags: performance, async, promises, nodejs
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Async/Await for I/O Operations
|
|
9
|
+
|
|
10
|
+
Always use async/await for I/O operations to avoid blocking the event loop and improve performance.
|
|
11
|
+
|
|
12
|
+
**Incorrect (blocking synchronous code):**
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
|
|
17
|
+
app.get('/api/file', (req, res) => {
|
|
18
|
+
// Blocks the entire server!
|
|
19
|
+
const data = fs.readFileSync('/large-file.json', 'utf8');
|
|
20
|
+
res.json(JSON.parse(data));
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Correct (non-blocking async):**
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
const fs = require('fs').promises;
|
|
28
|
+
|
|
29
|
+
app.get('/api/file', async (req, res) => {
|
|
30
|
+
try {
|
|
31
|
+
const data = await fs.readFile('/large-file.json', 'utf8');
|
|
32
|
+
res.json(JSON.parse(data));
|
|
33
|
+
} catch (error) {
|
|
34
|
+
res.status(500).json({ error: error.message });
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Parallel Async Operations:**
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
// Incorrect (sequential - slower)
|
|
43
|
+
const user = await User.findById(id);
|
|
44
|
+
const posts = await Post.find({ authorId: id });
|
|
45
|
+
const comments = await Comment.find({ userId: id });
|
|
46
|
+
|
|
47
|
+
// Correct (parallel - faster)
|
|
48
|
+
const [user, posts, comments] = await Promise.all([
|
|
49
|
+
User.findById(id),
|
|
50
|
+
Post.find({ authorId: id }),
|
|
51
|
+
Comment.find({ userId: id })
|
|
52
|
+
]);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Reference: [Async/Await Best Practices](https://javascript.info/async-await)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Implement Caching Strategies
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: 70-95% reduction in response time for cached data
|
|
5
|
+
tags: performance, caching, redis, optimization
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Implement Caching Strategies
|
|
9
|
+
|
|
10
|
+
Use caching to reduce database load and improve response times for frequently accessed data.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no caching - hits database every time):**
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
app.get('/api/products/:id', async (req, res) => {
|
|
16
|
+
// Queries database for every request
|
|
17
|
+
const product = await Product.findById(req.params.id);
|
|
18
|
+
res.json(product);
|
|
19
|
+
});
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (with Redis caching):**
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
const redis = require('redis');
|
|
26
|
+
const client = redis.createClient();
|
|
27
|
+
|
|
28
|
+
app.get('/api/products/:id', async (req, res) => {
|
|
29
|
+
const cacheKey = `product:${req.params.id}`;
|
|
30
|
+
|
|
31
|
+
// Try cache first
|
|
32
|
+
const cached = await client.get(cacheKey);
|
|
33
|
+
if (cached) {
|
|
34
|
+
return res.json(JSON.parse(cached));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// If not in cache, query database
|
|
38
|
+
const product = await Product.findById(req.params.id);
|
|
39
|
+
|
|
40
|
+
// Store in cache with 1 hour expiration
|
|
41
|
+
await client.setEx(cacheKey, 3600, JSON.stringify(product));
|
|
42
|
+
|
|
43
|
+
res.json(product);
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Cache Invalidation:**
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
app.put('/api/products/:id', async (req, res) => {
|
|
51
|
+
const product = await Product.findByIdAndUpdate(
|
|
52
|
+
req.params.id,
|
|
53
|
+
req.body,
|
|
54
|
+
{ new: true }
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Invalidate cache
|
|
58
|
+
await client.del(`product:${req.params.id}`);
|
|
59
|
+
|
|
60
|
+
res.json(product);
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**In-Memory Caching (node-cache):**
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
const NodeCache = require('node-cache');
|
|
68
|
+
const cache = new NodeCache({ stdTTL: 600 }); // 10 min default
|
|
69
|
+
|
|
70
|
+
app.get('/api/stats', async (req, res) => {
|
|
71
|
+
const cached = cache.get('stats');
|
|
72
|
+
if (cached) return res.json(cached);
|
|
73
|
+
|
|
74
|
+
const stats = await calculateStats(); // Expensive operation
|
|
75
|
+
cache.set('stats', stats);
|
|
76
|
+
|
|
77
|
+
res.json(stats);
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Reference: [Caching Best Practices](https://aws.amazon.com/caching/best-practices/)
|