Back to Dashboard

DEVELOPER ONBOARDING

NL-Dating API Developer Onboarding Guide

Welcome, Developer! 👋

This guide will help you get started with the NL-Dating API in just a few minutes.

Quick Start Checklist

  • [ ] Get API credentials
  • [ ] Import Postman collection
  • [ ] Make your first API call
  • [ ] Implement authentication
  • [ ] Build your first feature

Step 1: Get Your API Credentials

  1. Development Environment

    • Base URL: http://localhost:8000/api
    • No API key required for local development
  2. Production Environment

    • Base URL: https://api.nl-dating.com
    • Contact api-support@nl-dating.com for credentials

Step 2: Set Up Your Development Environment

Option A: Using Postman (Recommended for Testing)

  1. Download Postman
  2. Import our collection:
    • File → Import → Upload NL-Dating-API.postman_collection.json
  3. Set environment variables:
    • base_url: http://localhost:8000/api
    • access_token: (will be set automatically after login)

Option B: Using cURL

# Test the API is working
curl http://localhost:8000/api/health

# Create your first user
curl -X POST http://localhost:8000/api/mobile/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Test Developer",
    "email": "dev@example.com",
    "password": "SecurePass123!",
    "password_confirmation": "SecurePass123!",
    "birth_date": "1990-01-01",
    "gender": "male",
    "location": "Amsterdam",
    "interested_in": "female",
    "device_name": "Developer Test"
  }'

Step 3: Authentication Flow

1. Login and Get Token

// JavaScript Example
const response = await fetch('http://localhost:8000/api/mobile/auth/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: 'dev@example.com',
    password: 'SecurePass123!',
    device_name: 'My App'
  })
});

const data = await response.json();
const token = data.data.access_token; // Save this!

2. Use Token in Requests

// Always include the token in your requests
const profile = await fetch('http://localhost:8000/api/user/profile', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

Step 4: Your First Feature - Display User Profile

Here's a complete example of fetching and displaying a user profile:

React Example

import React, { useState, useEffect } from 'react';

function UserProfile() {
  const [profile, setProfile] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetchProfile();
  }, []);

  const fetchProfile = async () => {
    try {
      const token = localStorage.getItem('nl_dating_token');
      
      const response = await fetch('http://localhost:8000/api/user/profile', {
        headers: {
          'Authorization': `Bearer ${token}`
        }
      });

      if (!response.ok) {
        throw new Error('Failed to fetch profile');
      }

      const data = await response.json();
      setProfile(data.data);
    } catch (error) {
      console.error('Error:', error);
    } finally {
      setLoading(false);
    }
  };

  if (loading) return <div>Loading...</div>;
  if (!profile) return <div>Error loading profile</div>;

  return (
    <div className="profile">
      <img src={profile.basic_info.profile_photo_url} alt="Profile" />
      <h1>{profile.basic_info.full_name}</h1>
      <p>Age: {profile.basic_info.age}</p>
      <p>Location: {profile.basic_info.location}</p>
      <div className="progress">
        Profile Completion: {profile.meta.profile_completion}%
      </div>
    </div>
  );
}

Flutter Example

import 'package:http/http.dart' as http;
import 'dart:convert';

class ProfileService {
  final String baseUrl = 'http://localhost:8000/api';
  String? _token;

  Future<Map<String, dynamic>> getProfile() async {
    final response = await http.get(
      Uri.parse('$baseUrl/user/profile'),
      headers: {
        'Authorization': 'Bearer $_token',
      },
    );

    if (response.statusCode == 200) {
      final data = json.decode(response.body);
      return data['data'];
    } else {
      throw Exception('Failed to load profile');
    }
  }
}

// Usage in Widget
class ProfileScreen extends StatelessWidget {
  final ProfileService _service = ProfileService();

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Map<String, dynamic>>(
      future: _service.getProfile(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          final profile = snapshot.data!;
          return Column(
            children: [
              Text(profile['basic_info']['full_name']),
              Text('Age: ${profile['basic_info']['age']}'),
              Text('Location: ${profile['basic_info']['location']}'),
              LinearProgressIndicator(
                value: profile['meta']['profile_completion'] / 100,
              ),
            ],
          );
        }
        return CircularProgressIndicator();
      },
    );
  }
}

Step 5: Common Integration Patterns

1. Handling Token Expiration

class APIClient {
  async makeRequest(url, options = {}) {
    let response = await fetch(url, {
      ...options,
      headers: {
        ...options.headers,
        'Authorization': `Bearer ${this.token}`
      }
    });

    // Token expired
    if (response.status === 401) {
      await this.refreshToken();
      // Retry request with new token
      response = await fetch(url, {
        ...options,
        headers: {
          ...options.headers,
          'Authorization': `Bearer ${this.token}`
        }
      });
    }

    return response;
  }

  async refreshToken() {
    const response = await fetch('/api/mobile/auth/refresh', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${this.token}`
      },
      body: JSON.stringify({
        refresh_token: this.refreshToken
      })
    });

    const data = await response.json();
    this.token = data.data.access_token;
    this.refreshToken = data.data.refresh_token;
  }
}

2. Implementing Real-time Messaging

// Polling approach (simple)
class MessagingService {
  startPolling(userId) {
    setInterval(async () => {
      const messages = await this.getNewMessages(userId);
      if (messages.length > 0) {
        this.handleNewMessages(messages);
      }
    }, 5000); // Poll every 5 seconds
  }

  async getNewMessages(userId) {
    const response = await fetch(`/api/user/messages/${userId}?after=${this.lastMessageTime}`);
    const data = await response.json();
    return data.data.messages;
  }
}

3. Handling File Uploads

async function uploadProfilePhoto(file) {
  const formData = new FormData();
  formData.append('photo', file);
  formData.append('type', 'selfie');
  formData.append('is_primary', 'true');

  const response = await fetch('/api/user/photos/upload', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`
    },
    body: formData
  });

  return response.json();
}

Common Gotchas & Solutions

1. CORS Issues

Problem: "Access to fetch at ... has been blocked by CORS policy"

Solution:

  • Development: Ensure your frontend is running on an allowed origin
  • Production: Contact support to whitelist your domain

2. Rate Limiting

Problem: Getting 429 Too Many Requests

Solution:

// Implement exponential backoff
async function fetchWithRetry(url, options, retries = 3) {
  for (let i = 0; i < retries; i++) {
    const response = await fetch(url, options);
    
    if (response.status !== 429) {
      return response;
    }
    
    const retryAfter = response.headers.get('Retry-After') || Math.pow(2, i);
    await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
  }
  
  throw new Error('Rate limit exceeded');
}

3. Token Storage

Problem: Where to store tokens securely?

Solution:

  • Web: Use httpOnly cookies or secure localStorage with encryption
  • Mobile: Use Keychain (iOS) or Keystore (Android)
  • Never: Store in plain text or commit to version control

Testing Your Integration

1. Unit Tests

// Jest example
describe('ProfileAPI', () => {
  it('should fetch user profile', async () => {
    const mockProfile = {
      basic_info: { full_name: 'Test User' }
    };

    fetch.mockResponseOnce(JSON.stringify({
      success: true,
      data: mockProfile
    }));

    const profile = await profileAPI.getProfile();
    expect(profile.basic_info.full_name).toBe('Test User');
  });
});

2. Integration Tests

Use our Postman collection to create automated test suites:

  1. Import the collection
  2. Add test scripts to requests
  3. Run collection with Newman CLI

Need Help?

Resources

Support Channels

  • Email: api-support@nl-dating.com
  • Developer Forum: https://developers.nl-dating.com/forum
  • Stack Overflow: Tag your questions with nl-dating-api

Common Issues

What's Next?

Now that you're set up, try building:

  1. Profile Completion Flow: Help users complete their profiles
  2. Match Browser: Show potential matches with swipe functionality
  3. Chat Interface: Real-time messaging between matched users
  4. Meeting Scheduler: Book meetings at available venues

Happy coding! 🚀